Expose method for getting a 'safe' JSContext appropriate for use on the current thread. This will help travis fix bug 33489. r=brendan@mozilla.org.

This commit is contained in:
jband%netscape.com 2000-03-30 07:06:10 +00:00
Родитель 8acaad0615
Коммит 7ab8e93ba3
4 изменённых файлов: 237 добавлений и 221 удалений

Просмотреть файл

@ -40,8 +40,16 @@
[uuid(c67d8270-3189-11d3-9885-006008962422)]
interface nsIJSContextStack : nsISupports
{
readonly attribute PRInt32 Count;
JSContext Peek();
JSContext Pop();
void Push(in JSContext cx);
readonly attribute PRInt32 count;
JSContext peek();
JSContext pop();
void push(in JSContext cx);
};
[uuid(a1339ae0-05c1-11d4-8f92-0010a4e73d9a)]
interface nsIThreadJSContextStack : nsIJSContextStack
{
/* inherits methods of nsIJSContextStack */
readonly attribute JSContext safeJSContext;
};

Просмотреть файл

@ -46,135 +46,11 @@ nsXPConnect* nsXPConnect::gSelf = nsnull;
/***************************************************************************/
class xpcPerThreadData
{
public:
xpcPerThreadData();
~xpcPerThreadData();
nsIXPCException* GetException();
void SetException(nsIXPCException* aException);
JSContext* GetJSContext();
private:
nsIXPCException* mException;
JSContext* mCX;
};
xpcPerThreadData::xpcPerThreadData()
: mException(nsnull),
mCX(nsnull)
{
// empty...
}
xpcPerThreadData::~xpcPerThreadData()
{
NS_IF_RELEASE(mException);
if(mCX)
JS_DestroyContext(mCX);
}
nsIXPCException*
xpcPerThreadData::GetException()
{
NS_IF_ADDREF(mException);
return mException;
}
void
xpcPerThreadData::SetException(nsIXPCException* aException)
{
NS_IF_ADDREF(aException);
NS_IF_RELEASE(mException);
mException = aException;
}
static JSClass global_class = {
"globalForDefaultXPConnectJSContext", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
JSContext*
xpcPerThreadData::GetJSContext()
{
if(!mCX)
{
JSRuntime *rt;
nsresult rv;
NS_WITH_SERVICE(nsIJSRuntimeService, rtsvc, "nsJSRuntimeService", &rv);
if(NS_SUCCEEDED(rv) && NS_SUCCEEDED(rtsvc->GetRuntime(&rt)))
{
NS_WITH_SERVICE(nsIXPConnect, xpc, nsIXPConnect::GetCID(), &rv);
if(NS_SUCCEEDED(rv))
{
mCX = JS_NewContext(rt, 8192);
if(mCX)
{
JSObject *glob;
glob = JS_NewObject(mCX, &global_class, NULL, NULL);
if(!glob ||
!JS_InitStandardClasses(mCX, glob) ||
NS_FAILED(xpc->InitClasses(mCX, glob)))
{
JS_DestroyContext(mCX);
mCX = nsnull;
}
}
}
}
}
return mCX;
}
/*************************************************/
JS_STATIC_DLL_CALLBACK(void)
xpc_ThreadDataDtorCB(void* ptr)
{
xpcPerThreadData* data = (xpcPerThreadData*) ptr;
if(data)
delete data;
}
static xpcPerThreadData*
GetPerThreadData()
{
#define BAD_TLS_INDEX ((PRUintn) -1)
xpcPerThreadData* data;
static PRUintn index = BAD_TLS_INDEX;
if(index == BAD_TLS_INDEX)
{
if(PR_FAILURE == PR_NewThreadPrivateIndex(&index, xpc_ThreadDataDtorCB))
{
NS_ASSERTION(0, "PR_NewThreadPrivateIndex failed!");
return nsnull;
}
}
data = (xpcPerThreadData*) PR_GetThreadPrivate(index);
if(!data)
{
if(nsnull != (data = new xpcPerThreadData()))
{
if(PR_FAILURE == PR_SetThreadPrivate(index, data))
{
NS_ASSERTION(0, "PR_SetThreadPrivate failed!");
delete data;
data = nsnull;
}
}
else
{
NS_ASSERTION(0, "new xpcPerThreadData failed!");
}
}
return data;
}
/***************************************************************************/
// XXX In the worst case this makes 3 trips to get TLS (Thread Locl Storage).
// Since nsXPCThreadJSContextStackImpl is in our module and uses our
// xpcPerThreadData we could add static methods to nsXPCThreadJSContextStackImpl
// which take xpcPerThreadData as a param and do the below with only one trip
// to TLS.
AutoPushCompatibleJSContext::AutoPushCompatibleJSContext(JSRuntime* rt, nsXPConnect* xpc /*= nsnull*/)
: mCX(nsnull)
@ -183,34 +59,30 @@ AutoPushCompatibleJSContext::AutoPushCompatibleJSContext(JSRuntime* rt, nsXPConn
mContextStack = nsXPConnect::GetContextStack(xpc);
if(mContextStack)
{
JSContext* current;
JSContext* cx;
JSContext* safeCX;
if(NS_SUCCEEDED(mContextStack->Peek(&current)))
if(NS_SUCCEEDED(mContextStack->Peek(&cx)))
{
// Is the current runtime compatible?
if(current && JS_GetRuntime(current) == rt)
if(cx && JS_GetRuntime(cx) == rt)
{
mCX = current;
mCX = cx;
}
else
{
// The stack is either empty or the context is of the wrong
// runtime. Either way we need to *get* a compatible runtime
// and push it on the stack. xpconnect's per thread data will
// give us a JSContext.
// and push it on the stack.
xpcPerThreadData* data = GetPerThreadData();
if(data)
if(NS_SUCCEEDED(mContextStack->GetSafeJSContext(&safeCX)) &&
safeCX && JS_GetRuntime(safeCX) == rt &&
NS_SUCCEEDED(mContextStack->Push(safeCX)))
{
JSContext* ourCX = data->GetJSContext();
if(ourCX && JS_GetRuntime(ourCX) == rt &&
NS_SUCCEEDED(mContextStack->Push(ourCX)))
{
mCX = ourCX;
// Leave the reference to the mContextStack to
// indicate that we need to pop it in our dtor.
return;
}
mCX = safeCX;
// Leave the reference to the mContextStack to
// indicate that we need to pop it in our dtor.
return;
}
}
}
@ -268,7 +140,7 @@ nsXPConnect::nsXPConnect()
mThrower = new XPCJSThrower(JS_TRUE);
nsServiceManager::GetService("nsThreadJSContextStack",
NS_GET_IID(nsIJSContextStack),
NS_GET_IID(nsIThreadJSContextStack),
(nsISupports **)&mContextStack);
#ifdef XPC_TOOLS_SUPPORT
@ -378,11 +250,11 @@ nsXPConnect::ReleaseXPConnectSingleton()
if(GetRuntime() && GetRuntime()->GetJSRuntime())
{
AutoPushCompatibleJSContext a(GetRuntime()->GetJSRuntime());
if(a.GetJSContext())
if(a.GetSafeJSContext())
{
FILE* oldFileHandle = js_DumpGCHeap;
js_DumpGCHeap = stdout;
js_ForceGC(a.GetJSContext());
js_ForceGC(a.GetSafeJSContext());
js_DumpGCHeap = oldFileHandle;
}
}
@ -419,10 +291,10 @@ nsXPConnect::GetInterfaceInfoManager(nsXPConnect* xpc /*= nsnull*/)
}
// static
nsIJSContextStack*
nsIThreadJSContextStack*
nsXPConnect::GetContextStack(nsXPConnect* xpc /*= nsnull*/)
{
nsIJSContextStack* cs;
nsIThreadJSContextStack* cs;
nsXPConnect* xpcl = xpc;
if(!xpcl && !(xpcl = GetXPConnect()))
@ -764,7 +636,7 @@ nsXPConnect::GetPendingException(nsIXPCException * *aPendingException)
{
NS_ENSURE_ARG_POINTER(aPendingException);
xpcPerThreadData* data = GetPerThreadData();
xpcPerThreadData* data = xpcPerThreadData::GetData();
if(!data)
{
*aPendingException = nsnull;
@ -778,7 +650,7 @@ nsXPConnect::GetPendingException(nsIXPCException * *aPendingException)
NS_IMETHODIMP
nsXPConnect::SetPendingException(nsIXPCException * aPendingException)
{
xpcPerThreadData* data = GetPerThreadData();
xpcPerThreadData* data = xpcPerThreadData::GetData();
if(!data)
return NS_ERROR_FAILURE;
@ -884,13 +756,13 @@ nsXPConnect::DebugDumpJSStack(PRBool showArgs, PRBool showLocals, PRBool showThi
#ifdef DEBUG
JSContext* cx;
nsresult rv;
NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", &rv);
NS_WITH_SERVICE(nsIThreadJSContextStack, stack, "nsThreadJSContextStack", &rv);
if(NS_FAILED(rv))
printf("failed to get nsIJSContextStack service!\n");
printf("failed to get nsIThreadJSContextStack service!\n");
else if(NS_FAILED(stack->Peek(&cx)))
printf("failed to peek into nsIJSContextStack service!\n");
printf("failed to peek into nsIThreadJSContextStack service!\n");
else if(!cx)
printf("there is no JSContext on the nsIJSContextStack!\n");
printf("there is no JSContext on the nsIThreadJSContextStack!\n");
else
xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
#endif
@ -904,13 +776,13 @@ nsXPConnect::DebugDumpEvalInJSStackFrame(PRUint32 aFrameNumber, const char *aSou
#ifdef DEBUG
JSContext* cx;
nsresult rv;
NS_WITH_SERVICE(nsIJSContextStack, stack, "nsThreadJSContextStack", &rv);
NS_WITH_SERVICE(nsIThreadJSContextStack, stack, "nsThreadJSContextStack", &rv);
if(NS_FAILED(rv))
printf("failed to get nsIJSContextStack service!\n");
printf("failed to get nsIThreadJSContextStack service!\n");
else if(NS_FAILED(stack->Peek(&cx)))
printf("failed to peek into nsIJSContextStack service!\n");
printf("failed to peek into nsIThreadJSContextStack service!\n");
else if(!cx)
printf("there is no JSContext on the nsIJSContextStack!\n");
printf("there is no JSContext on the nsIThreadJSContextStack!\n");
else
xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText);
#endif

Просмотреть файл

@ -135,7 +135,7 @@ public:
// these all return an AddRef'd object (or nsnull on failure)
static nsXPConnect* GetXPConnect();
static nsIInterfaceInfoManager* GetInterfaceInfoManager(nsXPConnect* xpc = nsnull);
static nsIJSContextStack* GetContextStack(nsXPConnect* xpc = nsnull);
static nsIThreadJSContextStack* GetContextStack(nsXPConnect* xpc = nsnull);
static XPCJSThrower* GetJSThrower(nsXPConnect* xpc = nsnull);
static XPCJSRuntime* GetRuntime(nsXPConnect* xpc = nsnull);
static XPCContext* GetContext(JSContext* cx, nsXPConnect* xpc = nsnull);
@ -167,7 +167,7 @@ private:
nsIXPCScriptable* mArbitraryScriptable;
nsIInterfaceInfoManager* mInterfaceInfoManager;
XPCJSThrower* mThrower;
nsIJSContextStack* mContextStack;
nsIThreadJSContextStack* mContextStack;
nsIXPCSecurityManager* mDefaultSecurityManager;
PRUint16 mDefaultSecurityManagerFlags;
#ifdef XPC_TOOLS_SUPPORT
@ -424,7 +424,7 @@ private:
AutoPushJSContext(); // no implementation
private:
nsIJSContextStack* mContextStack;
nsIThreadJSContextStack* mContextStack;
#ifdef DEBUG
JSContext* mDebugCX;
#endif
@ -459,7 +459,7 @@ private:
AutoPushCompatibleJSContext(); // no implementation
private:
nsIJSContextStack* mContextStack;
nsIThreadJSContextStack* mContextStack;
JSContext* mCX;
};
@ -1339,21 +1339,54 @@ private:
/***************************************************************************/
// All of our thread local storage.
class xpcPerThreadData
{
public:
// Get the instance of this object for the current thread
static xpcPerThreadData* GetData();
xpcPerThreadData();
~xpcPerThreadData();
nsIXPCException* GetException();
void SetException(nsIXPCException* aException);
JSContext* GetSafeJSContext();
nsDeque* GetJSContextStack();
PRBool IsValid() const;
private:
nsIXPCException* mException;
nsDeque* mJSContextStack;
JSContext* mSafeJSContext;
};
/**************************************************************/
#define NS_XPC_THREAD_JSCONTEXT_STACK_CID \
{ 0xff8c4d10, 0x3194, 0x11d3, \
{ 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
class nsXPCThreadJSContextStackImpl : public nsIJSContextStack
class nsXPCThreadJSContextStackImpl : public nsIThreadJSContextStack
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIJSCONTEXTSTACK
NS_DECL_NSITHREADJSCONTEXTSTACK
static nsXPCThreadJSContextStackImpl* GetSingleton();
static void FreeSingleton();
nsXPCThreadJSContextStackImpl();
virtual ~nsXPCThreadJSContextStackImpl();
private:
nsDeque* GetStackForCurrentThread()
{xpcPerThreadData* data = xpcPerThreadData::GetData();
return data ? data->GetJSContextStack() : nsnull;}
};
/***************************************************************************/

Просмотреть файл

@ -37,52 +37,6 @@
#include "xpcprivate.h"
JS_STATIC_DLL_CALLBACK(void)
xpc_StackDtorCB(void* ptr)
{
nsDeque* myStack = (nsDeque*) ptr;
if(myStack)
delete myStack;
}
static nsDeque*
GetMyStack()
{
#define BAD_TLS_INDEX ((PRUintn) -1)
nsDeque* myStack;
static PRUintn index = BAD_TLS_INDEX;
if(index == BAD_TLS_INDEX)
{
if(PR_FAILURE == PR_NewThreadPrivateIndex(&index, xpc_StackDtorCB))
{
NS_ASSERTION(0, "PR_NewThreadPrivateIndex failed!");
return nsnull;
}
}
myStack = (nsDeque*) PR_GetThreadPrivate(index);
if(!myStack)
{
if(nsnull != (myStack = new nsDeque(nsnull)))
{
if(PR_FAILURE == PR_SetThreadPrivate(index, myStack))
{
NS_ASSERTION(0, "PR_SetThreadPrivate failed!");
delete myStack;
myStack = nsnull;
}
}
else
{
NS_ASSERTION(0, "new nsDeque failed!");
}
}
return myStack;
}
/***************************************************************************/
/*
* This object holds state that we don't want to lose!
*
@ -91,7 +45,7 @@ GetMyStack()
* is using it.
*/
NS_IMPL_ISUPPORTS1(nsXPCThreadJSContextStackImpl, nsIJSContextStack)
NS_IMPL_ISUPPORTS2(nsXPCThreadJSContextStackImpl, nsIThreadJSContextStack, nsIJSContextStack)
static nsXPCThreadJSContextStackImpl* gXPCThreadJSContextStack = nsnull;
@ -144,7 +98,7 @@ nsXPCThreadJSContextStackImpl::GetCount(PRInt32 *aCount)
if(!aCount)
return NS_ERROR_NULL_POINTER;
nsDeque* myStack = GetMyStack();
nsDeque* myStack = GetStackForCurrentThread();
if(!myStack)
{
@ -163,7 +117,7 @@ nsXPCThreadJSContextStackImpl::Peek(JSContext * *_retval)
if(!_retval)
return NS_ERROR_NULL_POINTER;
nsDeque* myStack = GetMyStack();
nsDeque* myStack = GetStackForCurrentThread();
if(!myStack)
{
@ -183,7 +137,7 @@ nsXPCThreadJSContextStackImpl::Peek(JSContext * *_retval)
NS_IMETHODIMP
nsXPCThreadJSContextStackImpl::Pop(JSContext * *_retval)
{
nsDeque* myStack = GetMyStack();
nsDeque* myStack = GetStackForCurrentThread();
if(!myStack)
{
@ -205,7 +159,7 @@ nsXPCThreadJSContextStackImpl::Pop(JSContext * *_retval)
NS_IMETHODIMP
nsXPCThreadJSContextStackImpl::Push(JSContext * cx)
{
nsDeque* myStack = GetMyStack();
nsDeque* myStack = GetStackForCurrentThread();
if(!myStack)
return NS_ERROR_FAILURE;
@ -213,3 +167,152 @@ nsXPCThreadJSContextStackImpl::Push(JSContext * cx)
myStack->Push(cx);
return NS_OK;
}
/* readonly attribute JSContext SafeJSContext; */
NS_IMETHODIMP
nsXPCThreadJSContextStackImpl::GetSafeJSContext(JSContext * *aSafeJSContext)
{
NS_ASSERTION(aSafeJSContext, "loser!");
xpcPerThreadData* data = xpcPerThreadData::GetData();
if(!data)
{
*aSafeJSContext = nsnull;
return NS_ERROR_FAILURE;
}
JSContext* ptr = *aSafeJSContext = data->GetSafeJSContext();
return ptr ? NS_OK : NS_ERROR_FAILURE;
}
/***************************************************************************/
xpcPerThreadData::xpcPerThreadData()
: mException(nsnull),
mJSContextStack(new nsDeque(nsnull)),
mSafeJSContext(nsnull)
{
// empty...
}
xpcPerThreadData::~xpcPerThreadData()
{
NS_IF_RELEASE(mException);
if(mJSContextStack)
delete mJSContextStack;
if(mSafeJSContext)
JS_DestroyContext(mSafeJSContext);
}
PRBool
xpcPerThreadData::IsValid() const
{
return mJSContextStack != nsnull;
}
nsIXPCException*
xpcPerThreadData::GetException()
{
NS_IF_ADDREF(mException);
return mException;
}
void
xpcPerThreadData::SetException(nsIXPCException* aException)
{
NS_IF_ADDREF(aException);
NS_IF_RELEASE(mException);
mException = aException;
}
nsDeque*
xpcPerThreadData::GetJSContextStack()
{
return mJSContextStack;
}
/**************************/
static JSClass global_class = {
"global_for_xpcPerThreadData_SafeJSContext", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
};
JSContext*
xpcPerThreadData::GetSafeJSContext()
{
if(!mSafeJSContext)
{
JSRuntime *rt;
nsCOMPtr<nsIJSRuntimeService> rtsvc =
do_GetService("nsJSRuntimeService");
if(rtsvc && NS_SUCCEEDED(rtsvc->GetRuntime(&rt)) && rt)
{
nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
if(xpc)
{
mSafeJSContext = JS_NewContext(rt, 8192);
if(mSafeJSContext)
{
JSObject *glob;
glob = JS_NewObject(mSafeJSContext, &global_class, NULL, NULL);
if(!glob ||
!JS_InitStandardClasses(mSafeJSContext, glob) ||
NS_FAILED(xpc->InitClasses(mSafeJSContext, glob)))
{
JS_DestroyContext(mSafeJSContext);
mSafeJSContext = nsnull;
}
}
}
}
}
return mSafeJSContext;
}
JS_STATIC_DLL_CALLBACK(void)
xpc_ThreadDataDtorCB(void* ptr)
{
xpcPerThreadData* data = (xpcPerThreadData*) ptr;
if(data)
delete data;
}
// static
xpcPerThreadData*
xpcPerThreadData::GetData()
{
static const PRUintn BAD_TLS_INDEX = (PRUintn) -1;
static PRUintn index = BAD_TLS_INDEX;
xpcPerThreadData* data;
if(index == BAD_TLS_INDEX)
{
if(PR_FAILURE == PR_NewThreadPrivateIndex(&index, xpc_ThreadDataDtorCB))
{
NS_ASSERTION(0, "PR_NewThreadPrivateIndex failed!");
index = BAD_TLS_INDEX;
return nsnull;
}
}
data = (xpcPerThreadData*) PR_GetThreadPrivate(index);
if(!data)
{
data = new xpcPerThreadData();
if(!data || !data->IsValid())
{
NS_ASSERTION(0, "new xpcPerThreadData() failed!");
if(data)
delete data;
return nsnull;
}
if(PR_FAILURE == PR_SetThreadPrivate(index, data))
{
NS_ASSERTION(0, "PR_SetThreadPrivate failed!");
delete data;
return nsnull;
}
}
return data;
}