зеркало из https://github.com/mozilla/gecko-dev.git
fixes for bug 60303, bug 60356, bug 57370, and bug 58982 r=mccabe sr=hyatt sr=brendan
This commit is contained in:
Родитель
c1564bb79e
Коммит
947e54ba96
|
@ -163,6 +163,9 @@ interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
|
|||
readonly attribute nsIIDPtr IID;
|
||||
|
||||
void debugDump(in short depth);
|
||||
|
||||
void aggregatedQueryInterface(in nsIIDRef uuid,
|
||||
[iid_is(uuid),retval] out nsQIResult result);
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -436,5 +439,27 @@ interface nsIXPConnect : nsISupports
|
|||
* context to use to execute JavaScript.
|
||||
*/
|
||||
void setSafeJSContextForCurrentThread(in JSContextPtr cx);
|
||||
|
||||
/**
|
||||
* wrapJSAggregatedToNative is just like wrapJS except it is used in cases
|
||||
* where the JSObject is also aggregated to some native xpcom Object.
|
||||
* At present XBL is the only system that might want to do this.
|
||||
*
|
||||
* XXX write more!
|
||||
*
|
||||
* Returns:
|
||||
* success:
|
||||
* NS_OK
|
||||
* failure:
|
||||
* NS_ERROR_XPC_BAD_CONVERT_JS
|
||||
* NS_ERROR_FAILURE
|
||||
*/
|
||||
void
|
||||
wrapJSAggregatedToNative(in nsISupports aOuter,
|
||||
in JSContextPtr aJSContext,
|
||||
in JSObjectPtr aJSObj,
|
||||
in nsIIDRef aIID,
|
||||
[iid_is(aIID),retval] out nsQIResult result);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -91,6 +91,16 @@ static void SetupRegistry()
|
|||
|
||||
/***************************************************************************/
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
#define DoBeginRequest(cx) JS_BeginRequest((cx))
|
||||
#define DoEndRequest(cx) JS_EndRequest((cx))
|
||||
#else
|
||||
#define DoBeginRequest(cx) ((void)0)
|
||||
#define DoEndRequest(cx) ((void)0)
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
#define EXITCODE_RUNTIME_ERROR 3
|
||||
#define EXITCODE_FILE_NOT_FOUND 4
|
||||
|
||||
|
@ -226,6 +236,7 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
return JS_FALSE;
|
||||
argv[i] = STRING_TO_JSVAL(str);
|
||||
filename = JS_GetStringBytes(str);
|
||||
DoBeginRequest(cx);
|
||||
script = JS_CompileFile(cx, obj, filename);
|
||||
if (!script)
|
||||
ok = JS_FALSE;
|
||||
|
@ -233,6 +244,7 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
ok = JS_ExecuteScript(cx, obj, script, &result);
|
||||
JS_DestroyScript(cx, script);
|
||||
}
|
||||
DoEndRequest(cx);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -475,11 +487,13 @@ Process(JSContext *cx, JSObject *obj, char *filename)
|
|||
}
|
||||
}
|
||||
ungetc(ch, fh);
|
||||
DoBeginRequest(cx);
|
||||
script = JS_CompileFileHandle(cx, obj, filename, fh);
|
||||
if (script) {
|
||||
(void)JS_ExecuteScript(cx, obj, script, &result);
|
||||
JS_DestroyScript(cx, script);
|
||||
}
|
||||
DoEndRequest(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -504,8 +518,9 @@ Process(JSContext *cx, JSObject *obj, char *filename)
|
|||
}
|
||||
bufp += strlen(bufp);
|
||||
lineno++;
|
||||
} while (!JS_BufferIsCompilableUnit(cx, obj,
|
||||
buffer, strlen(buffer)));
|
||||
} while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
|
||||
|
||||
DoBeginRequest(cx);
|
||||
/* Clear any pending exception from previous failed compiles. */
|
||||
JS_ClearPendingException(cx);
|
||||
script = JS_CompileScript(cx, obj, buffer, strlen(buffer),
|
||||
|
@ -542,6 +557,7 @@ Process(JSContext *cx, JSObject *obj, char *filename)
|
|||
#endif
|
||||
JS_DestroyScript(cx, script);
|
||||
}
|
||||
DoEndRequest(cx);
|
||||
} while (!hitEOF && !gQuitting);
|
||||
fprintf(gOutFile, "\n");
|
||||
return;
|
||||
|
|
|
@ -539,7 +539,33 @@ nsXPConnect::WrapJS(JSContext * aJSContext, JSObject * aJSObj, const nsIID & aII
|
|||
|
||||
nsresult rv;
|
||||
if(!XPCConvert::JSObject2NativeInterface(aJSContext, result, aJSObj,
|
||||
&aIID, &rv))
|
||||
&aIID, nsnull, &rv))
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
|
||||
NS_IMETHODIMP
|
||||
nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter, JSContext * aJSContext, JSObject * aJSObj, const nsIID & aIID, void * *result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aOuter);
|
||||
NS_ENSURE_ARG_POINTER(aJSContext);
|
||||
NS_ENSURE_ARG_POINTER(aJSObj);
|
||||
NS_ENSURE_ARG_POINTER(result);
|
||||
|
||||
AUTO_PUSH_JSCONTEXT2(aJSContext, this);
|
||||
*result = nsnull;
|
||||
|
||||
// This also ensures that we have a valid runtime
|
||||
XPCContext* xpcc = GetContext(aJSContext, this);
|
||||
if(!xpcc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
SET_CALLER_NATIVE(xpcc);
|
||||
|
||||
nsresult rv;
|
||||
if(!XPCConvert::JSObject2NativeInterface(aJSContext, result, aJSObj,
|
||||
&aIID, aOuter, &rv))
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -692,7 +692,8 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
|
|||
if(!JSVAL_IS_OBJECT(s) || !(obj = JSVAL_TO_OBJECT(s)))
|
||||
return JS_FALSE;
|
||||
|
||||
return JSObject2NativeInterface(cx, (void**)d, obj, iid, pErr);
|
||||
return JSObject2NativeInterface(cx, (void**)d, obj, iid,
|
||||
nsnull, pErr);
|
||||
}
|
||||
default:
|
||||
NS_ASSERTION(0, "bad type");
|
||||
|
@ -810,7 +811,9 @@ XPCConvert::NativeInterface2JSObject(JSContext* cx,
|
|||
JSBool
|
||||
XPCConvert::JSObject2NativeInterface(JSContext* cx,
|
||||
void** dest, JSObject* src,
|
||||
const nsID* iid, nsresult* pErr)
|
||||
const nsID* iid,
|
||||
nsISupports* aOuter,
|
||||
nsresult* pErr)
|
||||
{
|
||||
NS_ASSERTION(cx, "bad param");
|
||||
NS_ASSERTION(dest, "bad param");
|
||||
|
@ -842,8 +845,12 @@ XPCConvert::JSObject2NativeInterface(JSContext* cx,
|
|||
|
||||
// else...
|
||||
|
||||
// does the JSObject have 'nsISupportness'? (as do DOM objects)
|
||||
if(GetISupportsFromJSObject(cx, src, &iface))
|
||||
// Does the JSObject have 'nsISupportness'? (as do DOM objects.)
|
||||
// Note that if we have a non-null aOuter then it means that we are
|
||||
// forcing the creation of a wrapper even if the object *does* have
|
||||
// 'nsISupportness'. This allows wrapJSAggregatedToNative to work
|
||||
// with JSObjects that happen to have 'nsISupportness'.
|
||||
if(!aOuter && GetISupportsFromJSObject(cx, src, &iface))
|
||||
{
|
||||
if(iface)
|
||||
return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
|
||||
|
@ -858,7 +865,7 @@ XPCConvert::JSObject2NativeInterface(JSContext* cx,
|
|||
if(xpcc)
|
||||
{
|
||||
nsXPCWrappedJS* wrappedJS =
|
||||
nsXPCWrappedJS::GetNewOrUsedWrapper(xpcc, src, *iid);
|
||||
nsXPCWrappedJS::GetNewOrUsedWrapper(xpcc, src, *iid, aOuter);
|
||||
if(wrappedJS)
|
||||
{
|
||||
*dest = NS_STATIC_CAST(nsXPTCStubBase*, wrappedJS);
|
||||
|
@ -973,7 +980,8 @@ XPCConvert::JSValToXPCException(JSContext* cx,
|
|||
{
|
||||
return NS_REINTERPRET_CAST(nsIXPCException*,
|
||||
nsXPCWrappedJS::GetNewOrUsedWrapper(xpcc, obj,
|
||||
NS_GET_IID(nsIXPCException)));
|
||||
NS_GET_IID(nsIXPCException),
|
||||
nsnull));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
* in some more global way at runtime.
|
||||
*/
|
||||
|
||||
struct ResultMap {nsresult rv; const char* name; const char* format;} map[] = {
|
||||
static struct ResultMap
|
||||
{nsresult rv; const char* name; const char* format;} map[] = {
|
||||
#define XPC_MSG_DEF(val, format) \
|
||||
{(val), #val, format},
|
||||
#include "xpc.msg"
|
||||
|
|
|
@ -277,6 +277,7 @@ XPCJSRuntime::SyncXPCContextList(JSContext* cx /* = nsnull */)
|
|||
if(cx && cx == cur)
|
||||
found = xpcc;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
|
|
@ -250,10 +250,12 @@ public:
|
|||
|
||||
#ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
|
||||
void DEBUG_AddWrappedNative(nsIXPConnectWrappedNative* wrapper)
|
||||
{JS_HashTableAdd(DEBUG_WrappedNativeHashtable, wrapper, wrapper);}
|
||||
{nsAutoLock lock(mMapLock);
|
||||
JS_HashTableAdd(DEBUG_WrappedNativeHashtable, wrapper, wrapper);}
|
||||
|
||||
void DEBUG_RemoveWrappedNative(nsIXPConnectWrappedNative* wrapper)
|
||||
{JS_HashTableRemove(DEBUG_WrappedNativeHashtable, wrapper);}
|
||||
{nsAutoLock lock(mMapLock);
|
||||
JS_HashTableRemove(DEBUG_WrappedNativeHashtable, wrapper);}
|
||||
|
||||
private:
|
||||
JSHashTable *DEBUG_WrappedNativeHashtable;
|
||||
|
@ -751,7 +753,7 @@ public:
|
|||
NS_DECL_NSIXPCONNECTWRAPPEDJS
|
||||
|
||||
// Note that both nsXPTCStubBase and nsIXPConnectWrappedJS declare
|
||||
// a GetInterfaceInfo methos\d with the same sig. So, the declaration
|
||||
// GetInterfaceInfo methods with the same sig. So, the declaration
|
||||
// for it here comes from the NS_DECL_NSIXPCONNECTWRAPPEDJS macro
|
||||
|
||||
NS_IMETHOD CallMethod(PRUint16 methodIndex,
|
||||
|
@ -765,7 +767,8 @@ public:
|
|||
*/
|
||||
static nsXPCWrappedJS* GetNewOrUsedWrapper(XPCContext* xpcc,
|
||||
JSObject* aJSObj,
|
||||
REFNSIID aIID);
|
||||
REFNSIID aIID,
|
||||
nsISupports* aOuter);
|
||||
|
||||
JSObject* GetJSObject() const {return mJSObj;}
|
||||
nsXPCWrappedJSClass* GetClass() const {return mClass;}
|
||||
|
@ -773,23 +776,29 @@ public:
|
|||
nsXPCWrappedJS* GetRootWrapper() const {return mRoot;}
|
||||
|
||||
nsXPCWrappedJS* Find(REFNSIID aIID);
|
||||
nsXPCWrappedJS* FindInherited(REFNSIID aIID);
|
||||
|
||||
JSBool IsValid() const {return mJSObj != nsnull;}
|
||||
void SystemIsBeingShutDown(JSRuntime* rt);
|
||||
|
||||
JSBool IsAggregatedToNative() const {return mRoot->mOuter != nsnull;}
|
||||
nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
|
||||
|
||||
virtual ~nsXPCWrappedJS();
|
||||
private:
|
||||
nsXPCWrappedJS(); // not implemented
|
||||
nsXPCWrappedJS(XPCContext* xpcc,
|
||||
JSObject* aJSObj,
|
||||
nsXPCWrappedJSClass* aClass,
|
||||
nsXPCWrappedJS* root);
|
||||
nsXPCWrappedJS* root,
|
||||
nsISupports* aOuter);
|
||||
|
||||
private:
|
||||
JSObject* mJSObj;
|
||||
nsXPCWrappedJSClass* mClass;
|
||||
nsXPCWrappedJS* mRoot;
|
||||
nsXPCWrappedJS* mNext;
|
||||
nsISupports* mOuter; // only set in root
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -1125,7 +1134,9 @@ public:
|
|||
|
||||
static JSBool JSObject2NativeInterface(JSContext* cx,
|
||||
void** dest, JSObject* src,
|
||||
const nsID* iid, nsresult* pErr);
|
||||
const nsID* iid,
|
||||
nsISupports* aOuter,
|
||||
nsresult* pErr);
|
||||
|
||||
static JSBool NativeArray2JS(JSContext* cx,
|
||||
jsval* d, const void** s,
|
||||
|
@ -1373,6 +1384,8 @@ public:
|
|||
private:
|
||||
xpcPerThreadData();
|
||||
|
||||
void SyncJSContexts();
|
||||
|
||||
private:
|
||||
nsIXPCException* mException;
|
||||
nsDeque* mJSContextStack;
|
||||
|
@ -1515,6 +1528,16 @@ private:
|
|||
nsCString mCategory;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
class AutoJSRequest
|
||||
{
|
||||
public:
|
||||
AutoJSRequest(JSContext* aCX)
|
||||
: mCX(JS_GetContextThread(aCX) ? (JS_BeginRequest(aCX), aCX) : nsnull) {}
|
||||
~AutoJSRequest() { if(mCX) JS_EndRequest(mCX); }
|
||||
private:
|
||||
JSContext* mCX;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
// the include of declarations of the maps comes last because they have
|
||||
|
|
|
@ -222,8 +222,10 @@ xpcPerThreadData::Cleanup()
|
|||
|
||||
if(mOwnSafeJSContext)
|
||||
{
|
||||
JS_SetContextThread(mOwnSafeJSContext);
|
||||
JS_DestroyContext(mOwnSafeJSContext);
|
||||
mOwnSafeJSContext = nsnull;
|
||||
SyncJSContexts();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,6 +312,7 @@ xpcPerThreadData::GetSafeJSContext()
|
|||
mSafeJSContext = JS_NewContext(rt, 8192);
|
||||
if(mSafeJSContext)
|
||||
{
|
||||
AutoJSRequest req(mSafeJSContext); // scoped JS Request
|
||||
JSObject *glob;
|
||||
glob = JS_NewObject(mSafeJSContext, &global_class, NULL, NULL);
|
||||
if(!glob ||
|
||||
|
@ -342,6 +345,7 @@ xpcPerThreadData::SetSafeJSContext(JSContext *cx)
|
|||
{
|
||||
JS_DestroyContext(mOwnSafeJSContext);
|
||||
mOwnSafeJSContext = nsnull;
|
||||
SyncJSContexts();
|
||||
}
|
||||
|
||||
mSafeJSContext = cx;
|
||||
|
@ -421,3 +425,10 @@ xpcPerThreadData::CleanupAllThreads()
|
|||
PR_SetThreadPrivate(gTLSIndex, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
xpcPerThreadData::SyncJSContexts()
|
||||
{
|
||||
nsCOMPtr<nsXPConnect> xpc = dont_AddRef(nsXPConnect::GetXPConnect());
|
||||
if(xpc)
|
||||
xpc->SyncJSContexts();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,29 @@
|
|||
|
||||
// NOTE: much of the fancy footwork is done in xpcstubs.cpp
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCWrappedJS::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
NS_ASSERTION(IsAggregatedToNative(), "bad AggregatedQueryInterface call");
|
||||
|
||||
if(!IsValid())
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Put this here rather that in DelegatedQueryInterface because it needs
|
||||
// to be in QueryInterface before the possible delegation to 'outer', but
|
||||
// we don't want to do this check twice in one call in the normal case:
|
||||
// once in QueryInterface and once in DelegatedQueryInterface.
|
||||
if(aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS)))
|
||||
{
|
||||
NS_ADDREF(this);
|
||||
*aInstancePtr = (void*) NS_STATIC_CAST(nsIXPConnectWrappedJS*,this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
|
@ -52,25 +75,25 @@ nsXPCWrappedJS::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Always check for this first so that our 'outer' can get this interface
|
||||
// from us without recurring into a call to the outer's QI!
|
||||
if(aIID.Equals(NS_GET_IID(nsIXPConnectWrappedJS)))
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
NS_ADDREF(this);
|
||||
*aInstancePtr = (void*) NS_STATIC_CAST(nsIXPConnectWrappedJS*,this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if(aIID.Equals(NS_GET_IID(nsIXPConnectJSObjectHolder)))
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
*aInstancePtr = (void*) NS_STATIC_CAST(nsIXPConnectJSObjectHolder*,this);
|
||||
return NS_OK;
|
||||
}
|
||||
nsISupports* outer = GetAggregatedNativeObject();
|
||||
if(outer)
|
||||
return outer->QueryInterface(aIID, aInstancePtr);
|
||||
|
||||
// else...
|
||||
|
||||
return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
|
||||
// do chained ref counting
|
||||
|
||||
nsrefcnt
|
||||
|
@ -90,6 +113,11 @@ nsXPCWrappedJS::Release(void)
|
|||
{
|
||||
NS_PRECONDITION(mRoot, "bad root");
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
|
||||
#ifdef DEBUG_jband
|
||||
NS_ASSERTION(IsValid(), "post xpconnect shutdown call of nsXPCWrappedJS::Release");
|
||||
#endif
|
||||
|
||||
nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
|
||||
NS_LOG_RELEASE(this, cnt, "nsXPCWrappedJS");
|
||||
if(0 == cnt)
|
||||
|
@ -121,7 +149,8 @@ nsXPCWrappedJS::GetJSObject(JSObject** aJSObj)
|
|||
nsXPCWrappedJS*
|
||||
nsXPCWrappedJS::GetNewOrUsedWrapper(XPCContext* xpcc,
|
||||
JSObject* aJSObj,
|
||||
REFNSIID aIID)
|
||||
REFNSIID aIID,
|
||||
nsISupports* aOuter)
|
||||
{
|
||||
JSObject2WrappedJSMap* map;
|
||||
JSObject* rootJSObj;
|
||||
|
@ -173,7 +202,8 @@ nsXPCWrappedJS::GetNewOrUsedWrapper(XPCContext* xpcc,
|
|||
if(rootJSObj == aJSObj)
|
||||
{
|
||||
// the root will do double duty as the interface wrapper
|
||||
wrapper = root = new nsXPCWrappedJS(xpcc, aJSObj, clazz, nsnull);
|
||||
wrapper = root = new nsXPCWrappedJS(xpcc, aJSObj, clazz, nsnull,
|
||||
aOuter);
|
||||
if(root)
|
||||
{ // scoped lock
|
||||
nsAutoLock lock(rt->GetMapLock());
|
||||
|
@ -190,7 +220,7 @@ nsXPCWrappedJS::GetNewOrUsedWrapper(XPCContext* xpcc,
|
|||
if(!rootClazz)
|
||||
goto return_wrapper;
|
||||
|
||||
root = new nsXPCWrappedJS(xpcc, rootJSObj, rootClazz, nsnull);
|
||||
root = new nsXPCWrappedJS(xpcc, rootJSObj, rootClazz, nsnull, aOuter);
|
||||
NS_RELEASE(rootClazz);
|
||||
|
||||
if(!root)
|
||||
|
@ -208,7 +238,7 @@ nsXPCWrappedJS::GetNewOrUsedWrapper(XPCContext* xpcc,
|
|||
|
||||
if(!wrapper)
|
||||
{
|
||||
wrapper = new nsXPCWrappedJS(xpcc, aJSObj, clazz, root);
|
||||
wrapper = new nsXPCWrappedJS(xpcc, aJSObj, clazz, root, aOuter);
|
||||
if(!wrapper)
|
||||
goto return_wrapper;
|
||||
}
|
||||
|
@ -229,11 +259,13 @@ return_wrapper:
|
|||
nsXPCWrappedJS::nsXPCWrappedJS(XPCContext* xpcc,
|
||||
JSObject* aJSObj,
|
||||
nsXPCWrappedJSClass* aClass,
|
||||
nsXPCWrappedJS* root)
|
||||
nsXPCWrappedJS* root,
|
||||
nsISupports* aOuter)
|
||||
: mJSObj(aJSObj),
|
||||
mClass(aClass),
|
||||
mRoot(root ? root : this),
|
||||
mNext(nsnull)
|
||||
mNext(nsnull),
|
||||
mOuter(root ? nsnull : aOuter)
|
||||
{
|
||||
#ifdef DEBUG_stats_jband
|
||||
static int count = 0;
|
||||
|
@ -245,6 +277,7 @@ nsXPCWrappedJS::nsXPCWrappedJS(XPCContext* xpcc,
|
|||
NS_INIT_REFCNT();
|
||||
NS_ADDREF_THIS();
|
||||
NS_ADDREF(aClass);
|
||||
NS_IF_ADDREF(mOuter);
|
||||
NS_ASSERTION(xpcc && xpcc->GetJSContext(), "bad context");
|
||||
JS_AddNamedRoot(xpcc->GetJSContext(), &mJSObj,
|
||||
"nsXPCWrappedJS::mJSObj");
|
||||
|
@ -271,6 +304,9 @@ nsXPCWrappedJS::~nsXPCWrappedJS()
|
|||
JS_RemoveRootRT(rt->GetJSRuntime(), &mJSObj);
|
||||
}
|
||||
NS_IF_RELEASE(mClass);
|
||||
// XXX Should this moved out of the 'if' block?
|
||||
// XXX OR... Should this called in SystemIsBeingShutDown?
|
||||
NS_IF_RELEASE(mOuter);
|
||||
}
|
||||
if(mNext)
|
||||
NS_DELETEXPCOM(mNext); // cascaded delete
|
||||
|
@ -282,13 +318,37 @@ nsXPCWrappedJS::Find(REFNSIID aIID)
|
|||
if(aIID.Equals(NS_GET_IID(nsISupports)))
|
||||
return mRoot;
|
||||
|
||||
nsXPCWrappedJS* cur = mRoot;
|
||||
do
|
||||
for(nsXPCWrappedJS* cur = mRoot; cur; cur = cur->mNext)
|
||||
{
|
||||
if(aIID.Equals(cur->GetIID()))
|
||||
return cur;
|
||||
}
|
||||
|
||||
} while(nsnull != (cur = cur->mNext));
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// check if asking for an interface that some wrapper in the chain inherits from
|
||||
nsXPCWrappedJS*
|
||||
nsXPCWrappedJS::FindInherited(REFNSIID aIID)
|
||||
{
|
||||
NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)), "bad call sequence");
|
||||
|
||||
for(nsXPCWrappedJS* cur = mRoot; cur; cur = cur->mNext)
|
||||
{
|
||||
nsCOMPtr<nsIInterfaceInfo> iface = cur->GetClass()->GetInterfaceInfo();
|
||||
nsCOMPtr<nsIInterfaceInfo> iface_parent;
|
||||
|
||||
// Skip the first iface - we know we don't care about nsISupports here.
|
||||
while(NS_SUCCEEDED(iface->GetParent(getter_AddRefs(iface_parent))) &&
|
||||
iface_parent)
|
||||
{
|
||||
iface = iface_parent;
|
||||
|
||||
PRBool found;
|
||||
if(NS_SUCCEEDED(iface->IsIID(&aIID, &found)) && found)
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
@ -391,4 +451,3 @@ nsXPCWrappedJS::DebugDump(PRInt16 depth)
|
|||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,14 +91,10 @@ nsXPCWrappedJSClass::GetNewOrUsedClass(XPCJSRuntime* rt,
|
|||
nsAutoLock lock(rt->GetMapLock());
|
||||
IID2WrappedJSClassMap* map = rt->GetWrappedJSClassMap();
|
||||
clazz = map->Find(aIID);
|
||||
NS_IF_ADDREF(clazz);
|
||||
}
|
||||
|
||||
|
||||
if(clazz)
|
||||
{
|
||||
NS_ADDREF(clazz);
|
||||
}
|
||||
else
|
||||
if(!clazz)
|
||||
{
|
||||
nsCOMPtr<nsIInterfaceInfoManager> iimgr =
|
||||
dont_AddRef(nsXPConnect::GetInterfaceInfoManager());
|
||||
|
@ -279,18 +275,15 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
|||
REFNSIID aIID,
|
||||
void** aInstancePtr)
|
||||
{
|
||||
nsXPCWrappedJS* sibling;
|
||||
|
||||
// This includes checking for nsISupports and the iid of self.
|
||||
// And it also checks for other wrappers that have been constructed
|
||||
// for this object.
|
||||
if(nsnull != (sibling = self->Find(aIID)))
|
||||
if(aIID.Equals(NS_GET_IID(nsIXPConnectJSObjectHolder)))
|
||||
{
|
||||
NS_ADDREF(sibling);
|
||||
*aInstancePtr = (void*) sibling;
|
||||
NS_ADDREF(self);
|
||||
*aInstancePtr = (void*) NS_STATIC_CAST(nsIXPConnectJSObjectHolder*,self);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Objects internal to xpconnect are the only objects that even know *how*
|
||||
// to ask for this iid. And none of them bother refcoutning the thing.
|
||||
if(aIID.Equals(NS_GET_IID(WrappedJSIdentity)))
|
||||
{
|
||||
// asking to find out if this is a wrapper object
|
||||
|
@ -298,40 +291,36 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// else...
|
||||
nsXPCWrappedJS* sibling;
|
||||
|
||||
// check if asking for an interface that we inherit from
|
||||
|
||||
nsCOMPtr<nsIInterfaceInfo> current = GetInterfaceInfo();
|
||||
nsCOMPtr<nsIInterfaceInfo> parent;
|
||||
|
||||
while(NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent)
|
||||
// Checks for any existing wrapper explicitly constructed for this iid.
|
||||
// This includes the current 'self' wrapper. This also deals with the
|
||||
// nsISupports case (for which it returns mRoot).
|
||||
if(nsnull != (sibling = self->Find(aIID)))
|
||||
{
|
||||
current = parent;
|
||||
|
||||
nsIID* iid;
|
||||
if(NS_SUCCEEDED(current->GetIID(&iid)) && iid)
|
||||
{
|
||||
PRBool found = aIID.Equals(*iid);
|
||||
nsMemory::Free(iid);
|
||||
if(found)
|
||||
{
|
||||
*aInstancePtr = (void*) self;
|
||||
NS_ADDREF(self);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
NS_ADDREF(sibling);
|
||||
*aInstancePtr = (void*) sibling;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// else...
|
||||
// Check if asking for an interface from which one of our wrappers inherits.
|
||||
if(nsnull != (sibling = self->FindInherited(aIID)))
|
||||
{
|
||||
NS_ADDREF(sibling);
|
||||
*aInstancePtr = (void*) sibling;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// else we do the more expensive stuff...
|
||||
|
||||
// check if the JSObject claims to implement this interface
|
||||
JSObject* jsobj = CallQueryInterfaceOnJSObject(self->GetJSObject(), aIID);
|
||||
if(jsobj)
|
||||
{
|
||||
AutoPushCompatibleJSContext autoContext(mRuntime->GetJSRuntime());
|
||||
JSContext* cx = autoContext.GetJSContext();
|
||||
if(cx && XPCConvert::JSObject2NativeInterface(cx, aInstancePtr,
|
||||
jsobj, &aIID, nsnull))
|
||||
if(cx && XPCConvert::JSObject2NativeInterface(cx, aInstancePtr, jsobj,
|
||||
&aIID, nsnull, nsnull))
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,12 +83,11 @@ nsXPCWrappedNativeClass::GetNewOrUsedClass(XPCContext* xpcc,
|
|||
nsAutoLock lock(rt->GetMapLock());
|
||||
IID2WrappedNativeClassMap* map = rt->GetWrappedNativeClassMap();
|
||||
clazz = map->Find(aIID);
|
||||
}
|
||||
|
||||
if(clazz)
|
||||
{
|
||||
NS_ADDREF(clazz);
|
||||
return clazz;
|
||||
if(clazz)
|
||||
{
|
||||
NS_ADDREF(clazz);
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInterfaceInfoManager> iimgr =
|
||||
|
@ -558,6 +557,14 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx,
|
|||
XPCJSRuntime* rt;
|
||||
nsXPConnect* xpc;
|
||||
|
||||
// This is used to gate calls to JS_SuspendRequest/JS_ResumeRequest
|
||||
// XXX Looking at cx->requestDepth is currently necessary because the DOM
|
||||
// nsJSContexts break the nice rules and don't do their work within
|
||||
// JS Requests. Calling JS_SuspendRequest with a zero requestDepth
|
||||
// would cause the requestDepth to wrap around to a big number and
|
||||
// Bad Things would happen.
|
||||
JSBool useJSRequest = JS_GetContextThread(cx) && cx->requestDepth;
|
||||
|
||||
#ifdef DEBUG_stats_jband
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
PRIntervalTime endTime = 0;
|
||||
|
@ -908,10 +915,16 @@ nsXPCWrappedNativeClass::CallWrappedMethod(JSContext* cx,
|
|||
ccdata.init(callee, vtblIndex, wrapper, cx, argc, argv, vp);
|
||||
oldccdata = cc->SetData(&ccdata);
|
||||
|
||||
if(useJSRequest)
|
||||
JS_SuspendRequest(cx);
|
||||
|
||||
// do the invoke
|
||||
invokeResult = XPTC_InvokeByIndex(callee, vtblIndex,
|
||||
paramCount, dispatchParams);
|
||||
|
||||
if(useJSRequest)
|
||||
JS_ResumeRequest(cx);
|
||||
|
||||
xpcc->SetLastResult(invokeResult);
|
||||
cc->SetData(oldccdata);
|
||||
|
||||
|
@ -1107,6 +1120,7 @@ JSObject*
|
|||
nsXPCWrappedNativeClass::NewFunObj(JSContext *cx, JSObject *obj,
|
||||
const XPCNativeMemberDescriptor* desc)
|
||||
{
|
||||
JSFunction *fun;
|
||||
NS_ASSERTION(desc->IsMethod(), "we can only create FunObjs for methods");
|
||||
|
||||
if(-1 == desc->argc)
|
||||
|
@ -1125,10 +1139,13 @@ nsXPCWrappedNativeClass::NewFunObj(JSContext *cx, JSObject *obj,
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
JSFunction *fun = JS_NewFunction(cx, WrappedNative_CallMethod,
|
||||
(uintN) desc->argc,
|
||||
JSFUN_BOUND_METHOD, obj,
|
||||
GetMemberName(desc));
|
||||
{
|
||||
AutoJSRequest req(cx); // scoped JS Request
|
||||
fun = JS_NewFunction(cx, WrappedNative_CallMethod,
|
||||
(uintN) desc->argc,
|
||||
JSFUN_BOUND_METHOD, obj,
|
||||
GetMemberName(desc));
|
||||
}
|
||||
if(!fun)
|
||||
return nsnull;
|
||||
return JS_GetFunctionObject(fun);
|
||||
|
@ -1269,6 +1286,7 @@ nsXPCWrappedNativeClass::NewInstanceJSObject(XPCContext* xpcc,
|
|||
JSObject* aGlobalObject,
|
||||
nsXPCWrappedNative* self)
|
||||
{
|
||||
JSObject* jsobj;
|
||||
JSContext* cx = xpcc->GetJSContext();
|
||||
JSClass* jsclazz = self->GetDynamicScriptable() ?
|
||||
&WrappedNativeWithCall_class :
|
||||
|
@ -1279,8 +1297,11 @@ nsXPCWrappedNativeClass::NewInstanceJSObject(XPCContext* xpcc,
|
|||
// after creation. If we just pass nsnull as the prototype argument, the
|
||||
// engine will do a scope search for the class name to find the constructor,
|
||||
// which is an expense we don't need, and will always fail anyway.
|
||||
|
||||
JSObject* jsobj = JS_NewObject(cx, jsclazz, aGlobalObject, aGlobalObject);
|
||||
|
||||
{
|
||||
AutoJSRequest req(cx); // scoped JS Request
|
||||
jsobj = JS_NewObject(cx, jsclazz, aGlobalObject, aGlobalObject);
|
||||
}
|
||||
if(!jsobj || !JS_SetPrototype(cx, jsobj, nsnull) ||
|
||||
!JS_SetPrivate(cx, jsobj, self))
|
||||
return nsnull;
|
||||
|
|
|
@ -772,6 +772,14 @@ WrappedNative_Finalize(JSContext *cx, JSObject *obj)
|
|||
if(!wrapper || !wrapper->IsValid())
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
static const int FREQUENCY = 50;
|
||||
static int hit_count = 0;
|
||||
//if(!(++hit_count % FREQUENCY))
|
||||
// NS_ASSERTION(0, "ignore me and see me crash!");
|
||||
}
|
||||
#endif
|
||||
// Defer this push until we know we have a valid wrapper to work with.
|
||||
// This call can *startup* XPConnect after it has been shutdown!
|
||||
AUTO_PUSH_JSCONTEXT(cx);
|
||||
|
|
Загрузка…
Ссылка в новой задаче