When pushing on top of a JSContext on the XPConnect JSContext stack, save offthe JSStackFrame chain on that JSContext. When popping, restore the stackframe chain. Bug 371858, r=jst, sr=brendan

This commit is contained in:
bzbarsky@mit.edu 2007-05-04 22:55:47 -07:00
parent b1563bdb95
commit 5a7814a82a
2 changed files with 60 additions and 35 deletions

View File

@ -108,6 +108,7 @@
#include "nsIPropertyBag.h"
#include "nsIProperty.h"
#include "nsSupportsArray.h"
#include "nsTArray.h"
#include "nsIXPCScriptNotify.h" // used to notify: ScriptEvaluated
@ -2772,6 +2773,15 @@ private:
/***************************************************************************/
// XPCJSContextStack is not actually an xpcom object, but xpcom calls are
// delegated to it as an implementation detail.
struct JSContextAndFrame {
JSContextAndFrame(JSContext* aCx) :
cx(aCx),
frame(nsnull)
{}
JSContext* cx;
JSStackFrame* frame; // Frame to be restored when this JSContext becomes
// the topmost one.
};
class XPCJSContextStack
{
@ -2786,14 +2796,14 @@ public:
JSBool DEBUG_StackHasJSContext(JSContext* aJSContext);
#endif
const nsDeque &GetStack()
{ return mStack; }
const nsTArray<JSContextAndFrame>* GetStack()
{ return &mStack; }
private:
void SyncJSContexts();
private:
nsDeque mStack;
nsTArray<JSContextAndFrame> mStack;
JSContext* mSafeJSContext;
// If non-null, we own it; same as mSafeJSContext if SetSafeJSContext
@ -2814,8 +2824,8 @@ public:
NS_DECL_NSIJSCONTEXTSTACKITERATOR
private:
// XXX These don't really want to be pointers.
nsAutoPtr<nsDequeIterator> mIterator;
const nsTArray<JSContextAndFrame> *mStack;
PRUint32 mPosition;
};
/**************************************************************/

View File

@ -46,7 +46,7 @@
/***************************************************************************/
XPCJSContextStack::XPCJSContextStack()
: mStack(nsnull),
: mStack(),
mSafeJSContext(nsnull),
mOwnSafeJSContext(nsnull)
{
@ -76,7 +76,7 @@ XPCJSContextStack::SyncJSContexts()
NS_IMETHODIMP
XPCJSContextStack::GetCount(PRInt32 *aCount)
{
*aCount = mStack.GetSize();
*aCount = mStack.Length();
return NS_OK;
}
@ -84,7 +84,7 @@ XPCJSContextStack::GetCount(PRInt32 *aCount)
NS_IMETHODIMP
XPCJSContextStack::Peek(JSContext * *_retval)
{
*_retval = (JSContext*) mStack.Peek();
*_retval = mStack.IsEmpty() ? nsnull : mStack[mStack.Length() - 1].cx;
return NS_OK;
}
@ -92,12 +92,28 @@ XPCJSContextStack::Peek(JSContext * *_retval)
NS_IMETHODIMP
XPCJSContextStack::Pop(JSContext * *_retval)
{
NS_ASSERTION(mStack.GetSize() > 0, "ThreadJSContextStack underflow");
NS_ASSERTION(!mStack.IsEmpty(), "ThreadJSContextStack underflow");
PRUint32 idx = mStack.Length() - 1; // The thing we're popping
NS_ASSERTION(!mStack[idx].frame,
"Shouldn't have a pending frame to restore on the context "
"we're popping!");
if(_retval)
*_retval = (JSContext*) mStack.Pop();
else
mStack.Pop();
*_retval = mStack[idx].cx;
mStack.RemoveElementAt(idx);
if(idx > 0)
{
--idx; // Advance to new top of the stack
JSContextAndFrame & e = mStack[idx];
NS_ASSERTION(!e.frame || e.cx, "Shouldn't have frame without a cx!");
if(e.cx)
{
JS_RestoreFrameChain(e.cx, e.frame);
e.frame = nsnull;
}
}
return NS_OK;
}
@ -105,7 +121,14 @@ XPCJSContextStack::Pop(JSContext * *_retval)
NS_IMETHODIMP
XPCJSContextStack::Push(JSContext * cx)
{
mStack.Push(cx);
if(!mStack.AppendElement(cx))
return NS_ERROR_OUT_OF_MEMORY;
if(mStack.Length() > 1)
{
JSContextAndFrame & e = mStack[mStack.Length() - 2];
if(e.cx)
e.frame = JS_SaveFrameChain(e.cx);
}
return NS_OK;
}
@ -113,8 +136,8 @@ XPCJSContextStack::Push(JSContext * cx)
JSBool
XPCJSContextStack::DEBUG_StackHasJSContext(JSContext* aJSContext)
{
for(PRInt32 i = 0; i < mStack.GetSize(); i++)
if(aJSContext == (JSContext*)mStack.ObjectAt(i))
for(PRUint32 i = 0; i < mStack.Length(); i++)
if(aJSContext == mStack[i].cx)
return JS_TRUE;
return JS_FALSE;
}
@ -643,17 +666,11 @@ nsXPCJSContextStackIterator::Reset(nsIJSContextStack *aStack)
XPCJSContextStack *stack = impl->GetStackForCurrentThread();
if(!stack)
return NS_ERROR_FAILURE;
const nsDeque &deque = stack->GetStack();
if(deque.GetSize() == 0)
{
mIterator = nsnull;
return NS_OK;
}
mIterator = new nsDequeIterator(deque.End());
if(!mIterator)
return NS_ERROR_OUT_OF_MEMORY;
mStack = stack->GetStack();
if(mStack->IsEmpty())
mStack = nsnull;
else
mPosition = mStack->Length() - 1;
return NS_OK;
}
@ -661,25 +678,23 @@ nsXPCJSContextStackIterator::Reset(nsIJSContextStack *aStack)
NS_IMETHODIMP
nsXPCJSContextStackIterator::Done(PRBool *aDone)
{
*aDone = !mIterator;
*aDone = !mStack;
return NS_OK;
}
NS_IMETHODIMP
nsXPCJSContextStackIterator::Prev(JSContext **aContext)
{
if(!mIterator)
if(!mStack)
return NS_ERROR_NOT_INITIALIZED;
*aContext = (JSContext*)(mIterator->GetCurrent());
*aContext = mStack->ElementAt(mPosition).cx;
// XXX This temporary shouldn't be necessary.
nsDequeIterator first(*mIterator);
if(*mIterator == first.First())
mIterator = nsnull;
if(mPosition == 0)
mStack = nsnull;
else
--*mIterator;
--mPosition;
return NS_OK;
}