diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp index a4f49630914..167e5c014bb 100644 --- a/js/xpconnect/src/XPCCallContext.cpp +++ b/js/xpconnect/src/XPCCallContext.cpp @@ -40,8 +40,12 @@ /* Call context. */ +#include "mozilla/Util.h" + #include "xpcprivate.h" +using namespace mozilla; + XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, JSContext* cx /* = nsnull */, JSObject* obj /* = nsnull */, @@ -107,15 +111,15 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage, return; XPCJSContextStack* stack = mThreadData->GetJSContextStack(); - JSContext* topJSContext; - if (!stack || NS_FAILED(stack->Peek(&topJSContext))) { + if (!stack) { // If we don't have a stack we're probably in shutdown. - NS_ASSERTION(!stack, "Bad, Peek failed!"); mJSContext = nsnull; return; } + JSContext *topJSContext = stack->Peek(); + if (!mJSContext) { // This is slightly questionable. If called without an explicit // JSContext (generally a call to a wrappedJS) we will use the JSContext @@ -125,14 +129,17 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage, // have JS stack 'continuity' for purposes of stack traces etc. // Note: this *is* what the pre-XPCCallContext xpconnect did too. - if (topJSContext) + if (topJSContext) { mJSContext = topJSContext; - else if (NS_FAILED(stack->GetSafeJSContext(&mJSContext)) || !mJSContext) - return; + } else { + mJSContext = stack->GetSafeJSContext(); + if (!mJSContext) + return; + } } if (topJSContext != mJSContext) { - if (NS_FAILED(stack->Push(mJSContext))) { + if (!stack->Push(mJSContext)) { NS_ERROR("bad!"); return; } @@ -346,13 +353,8 @@ XPCCallContext::~XPCCallContext() XPCJSContextStack* stack = mThreadData->GetJSContextStack(); NS_ASSERTION(stack, "bad!"); if (stack) { -#ifdef DEBUG - JSContext* poppedCX; - nsresult rv = stack->Pop(&poppedCX); - NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == mJSContext, "bad pop"); -#else - (void) stack->Pop(nsnull); -#endif + DebugOnly poppedCX = stack->Pop(); + NS_ASSERTION(poppedCX == mJSContext, "bad pop"); } } @@ -519,10 +521,7 @@ XPCLazyCallContext::AssertContextIsTopOfStack(JSContext* cx) XPCPerThreadData* tls = XPCPerThreadData::GetData(cx); XPCJSContextStack* stack = tls->GetJSContextStack(); - JSContext* topJSContext; - nsresult rv = stack->Peek(&topJSContext); - NS_ASSERTION(NS_SUCCEEDED(rv), "XPCJSContextStack::Peek failed"); - + JSContext *topJSContext = stack->Peek(); NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!"); } #endif diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index c8a90a5cd2e..71c4eab7370 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -42,6 +42,8 @@ /* The "Components" xpcom objects for JavaScript. */ +#include "mozilla/unused.h" + #include "xpcprivate.h" #include "nsReadableUtils.h" #include "xpcIJSModuleLoader.h" @@ -59,6 +61,7 @@ #include "jsgc.h" #include "jsfriendapi.h" +using namespace mozilla; using namespace js; /***************************************************************************/ // stuff used by all @@ -3444,7 +3447,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, XPCPerThreadData *data = XPCPerThreadData::GetData(cx); XPCJSContextStack *stack = nsnull; if (data && (stack = data->GetJSContextStack())) { - if (NS_FAILED(stack->Push(sandcx->GetJSContext()))) { + if (!stack->Push(sandcx->GetJSContext())) { JS_ReportError(cx, "Unable to initialize XPConnect with the sandbox context"); JSPRINCIPALS_DROP(cx, jsPrincipals); @@ -3467,9 +3470,8 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, JSString *str = nsnull; if (!ac.enter(sandcx->GetJSContext(), sandbox)) { - if (stack) { - stack->Pop(nsnull); - } + if (stack) + unused << stack->Pop(); return NS_ERROR_FAILURE; } @@ -3545,9 +3547,8 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, } } - if (stack) { - stack->Pop(nsnull); - } + if (stack) + unused << stack->Pop(); JSPRINCIPALS_DROP(cx, jsPrincipals); diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index cb8aa922631..4430c90fae2 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -1125,9 +1125,7 @@ xpc_qsAssertContextOK(JSContext *cx) XPCPerThreadData *thread = XPCPerThreadData::GetData(cx); XPCJSContextStack* stack = thread->GetJSContextStack(); - JSContext* topJSContext = nsnull; - nsresult rv = stack->Peek(&topJSContext); - NS_ASSERTION(NS_SUCCEEDED(rv), "XPCJSContextStack::Peek failed"); + JSContext *topJSContext = stack->Peek(); // This is what we're actually trying to assert here. NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!"); diff --git a/js/xpconnect/src/XPCThreadContext.cpp b/js/xpconnect/src/XPCThreadContext.cpp index b3af6ca59f1..c85539817d6 100644 --- a/js/xpconnect/src/XPCThreadContext.cpp +++ b/js/xpconnect/src/XPCThreadContext.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=80: * * ***** BEGIN LICENSE BLOCK ***** @@ -52,14 +52,6 @@ using namespace mozilla; /***************************************************************************/ -XPCJSContextStack::XPCJSContextStack() - : mStack(), - mSafeJSContext(nsnull), - mOwnSafeJSContext(nsnull) -{ - // empty... -} - XPCJSContextStack::~XPCJSContextStack() { if (mOwnSafeJSContext) { @@ -69,54 +61,37 @@ XPCJSContextStack::~XPCJSContextStack() } } -/* readonly attribute PRInt32 count; */ -NS_IMETHODIMP -XPCJSContextStack::GetCount(PRInt32 *aCount) +JSContext* +XPCJSContextStack::Pop() { - *aCount = mStack.Length(); - return NS_OK; -} + MOZ_ASSERT(!mStack.IsEmpty()); -/* JSContext peek (); */ -NS_IMETHODIMP -XPCJSContextStack::Peek(JSContext * *_retval) -{ - *_retval = mStack.IsEmpty() ? nsnull : mStack[mStack.Length() - 1].cx; - return NS_OK; -} + uint32_t idx = mStack.Length() - 1; // The thing we're popping -/* JSContext pop (); */ -NS_IMETHODIMP -XPCJSContextStack::Pop(JSContext * *_retval) -{ - NS_ASSERTION(!mStack.IsEmpty(), "ThreadJSContextStack underflow"); - - PRUint32 idx = mStack.Length() - 1; // The thing we're popping - - if (_retval) - *_retval = mStack[idx].cx; + JSContext *cx = mStack[idx].cx; mStack.RemoveElementAt(idx); - if (idx > 0) { - --idx; // Advance to new top of the stack + if (idx == 0) + return cx; - XPCJSContextInfo & e = mStack[idx]; - NS_ASSERTION(!e.suspendDepth || e.cx, "Shouldn't have suspendDepth without a cx!"); - if (e.cx) { - if (e.suspendDepth) { - JS_ResumeRequest(e.cx, e.suspendDepth); - e.suspendDepth = 0; - } + --idx; // Advance to new top of the stack - if (e.savedFrameChain) { - // Pop() can be called outside any request for e.cx. - JSAutoRequest ar(e.cx); - JS_RestoreFrameChain(e.cx); - e.savedFrameChain = false; - } + XPCJSContextInfo &e = mStack[idx]; + NS_ASSERTION(!e.suspendDepth || e.cx, "Shouldn't have suspendDepth without a cx!"); + if (e.cx) { + if (e.suspendDepth) { + JS_ResumeRequest(e.cx, e.suspendDepth); + e.suspendDepth = 0; + } + + if (e.savedFrameChain) { + // Pop() can be called outside any request for e.cx. + JSAutoRequest ar(e.cx); + JS_RestoreFrameChain(e.cx); + e.savedFrameChain = false; } } - return NS_OK; + return cx; } static nsIPrincipal* @@ -131,53 +106,54 @@ GetPrincipalFromCx(JSContext *cx) return nsnull; } -/* void push (in JSContext cx); */ -NS_IMETHODIMP -XPCJSContextStack::Push(JSContext * cx) +bool +XPCJSContextStack::Push(JSContext *cx) { - JS_ASSERT_IF(cx, JS_GetContextThread(cx)); - if (mStack.Length() > 0) { - XPCJSContextInfo & e = mStack[mStack.Length() - 1]; - if (e.cx) { - if (e.cx == cx) { - nsIScriptSecurityManager* ssm = XPCWrapper::GetSecurityManager(); - if (ssm) { - if (nsIPrincipal* globalObjectPrincipal = GetPrincipalFromCx(cx)) { - nsIPrincipal* subjectPrincipal = ssm->GetCxSubjectPrincipal(cx); - bool equals = false; - globalObjectPrincipal->Equals(subjectPrincipal, &equals); - if (equals) { - goto append; - } + MOZ_ASSERT_IF(cx, JS_GetContextThread(cx)); + if (mStack.Length() == 0) { + mStack.AppendElement(cx); + return true; + } + + XPCJSContextInfo &e = mStack[mStack.Length() - 1]; + if (e.cx) { + if (e.cx == cx) { + nsIScriptSecurityManager* ssm = XPCWrapper::GetSecurityManager(); + if (ssm) { + if (nsIPrincipal* globalObjectPrincipal = GetPrincipalFromCx(cx)) { + nsIPrincipal* subjectPrincipal = ssm->GetCxSubjectPrincipal(cx); + bool equals = false; + globalObjectPrincipal->Equals(subjectPrincipal, &equals); + if (equals) { + mStack.AppendElement(cx); + return true; } } } - - { - // Push() can be called outside any request for e.cx. - JSAutoRequest ar(e.cx); - if (!JS_SaveFrameChain(e.cx)) - return NS_ERROR_OUT_OF_MEMORY; - e.savedFrameChain = true; - } - - if (!cx) - e.suspendDepth = JS_SuspendRequest(e.cx); } + + { + // Push() can be called outside any request for e.cx. + JSAutoRequest ar(e.cx); + if (!JS_SaveFrameChain(e.cx)) + return false; + e.savedFrameChain = true; + } + + if (!cx) + e.suspendDepth = JS_SuspendRequest(e.cx); } - append: - if (!mStack.AppendElement(cx)) - return NS_ERROR_OUT_OF_MEMORY; - return NS_OK; + mStack.AppendElement(cx); + return true; } #ifdef DEBUG -JSBool -XPCJSContextStack::DEBUG_StackHasJSContext(JSContext* aJSContext) +bool +XPCJSContextStack::DEBUG_StackHasJSContext(JSContext *cx) { for (PRUint32 i = 0; i < mStack.Length(); i++) - if (aJSContext == mStack[i].cx) + if (cx == mStack[i].cx) return true; return false; } @@ -211,88 +187,89 @@ static JSClass global_class = { extern void mozJSLoaderErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep); -/* attribute JSContext safeJSContext; */ -NS_IMETHODIMP -XPCJSContextStack::GetSafeJSContext(JSContext * *aSafeJSContext) +JSContext* +XPCJSContextStack::GetSafeJSContext() { - if (!mSafeJSContext) { - // Start by getting the principal holder and principal for this - // context. If we can't manage that, don't bother with the rest. - nsRefPtr principal = new nsNullPrincipal(); - nsCOMPtr sop; - if (principal) { - nsresult rv = principal->Init(); - if (NS_SUCCEEDED(rv)) - sop = new PrincipalHolder(principal); - } - if (!sop) { - *aSafeJSContext = nsnull; - return NS_ERROR_FAILURE; + if (mSafeJSContext) + return mSafeJSContext; + + // Start by getting the principal holder and principal for this + // context. If we can't manage that, don't bother with the rest. + nsRefPtr principal = new nsNullPrincipal(); + nsresult rv = principal->Init(); + if (NS_FAILED(rv)) + return NULL; + + nsCOMPtr sop = new PrincipalHolder(principal); + + nsRefPtr xpc = nsXPConnect::GetXPConnect(); + if (!xpc) + return NULL; + + XPCJSRuntime* xpcrt = xpc->GetRuntime(); + if (!xpcrt) + return NULL; + + JSRuntime *rt = xpcrt->GetJSRuntime(); + if (!rt) + return NULL; + + mSafeJSContext = JS_NewContext(rt, 8192); + if (!mSafeJSContext) + return NULL; + + JSObject *glob; + { + // scoped JS Request + JSAutoRequest req(mSafeJSContext); + + JS_SetErrorReporter(mSafeJSContext, mozJSLoaderErrorReporter); + + // Because we can run off the main thread, we create an MT + // global object. Our principal is the unique key. + JSCompartment *compartment; + nsresult rv = xpc_CreateMTGlobalObject(mSafeJSContext, + &global_class, + principal, &glob, + &compartment); + if (NS_FAILED(rv)) + glob = nsnull; + + if (glob) { + // Make sure the context is associated with a proper compartment + // and not the default compartment. + JS_SetGlobalObject(mSafeJSContext, glob); + + // Note: make sure to set the private before calling + // InitClasses + nsIScriptObjectPrincipal* priv = nsnull; + sop.swap(priv); + if (!JS_SetPrivate(mSafeJSContext, glob, priv)) { + // Drop the whole thing + NS_RELEASE(priv); + glob = nsnull; + } } - JSRuntime *rt; - XPCJSRuntime* xpcrt; - - nsXPConnect* xpc = nsXPConnect::GetXPConnect(); - nsCOMPtr xpcholder(static_cast(xpc)); - - if (xpc && (xpcrt = xpc->GetRuntime()) && (rt = xpcrt->GetJSRuntime())) { - JSObject *glob; - mSafeJSContext = JS_NewContext(rt, 8192); - if (mSafeJSContext) { - // scoped JS Request - JSAutoRequest req(mSafeJSContext); - - JS_SetErrorReporter(mSafeJSContext, mozJSLoaderErrorReporter); - - // Because we can run off the main thread, we create an MT - // global object. Our principal is the unique key. - JSCompartment *compartment; - nsresult rv = xpc_CreateMTGlobalObject(mSafeJSContext, - &global_class, - principal, &glob, - &compartment); - if (NS_FAILED(rv)) - glob = nsnull; - - if (glob) { - // Make sure the context is associated with a proper compartment - // and not the default compartment. - JS_SetGlobalObject(mSafeJSContext, glob); - - // Note: make sure to set the private before calling - // InitClasses - nsIScriptObjectPrincipal* priv = nsnull; - sop.swap(priv); - if (!JS_SetPrivate(mSafeJSContext, glob, priv)) { - // Drop the whole thing - NS_RELEASE(priv); - glob = nsnull; - } - } - - // After this point either glob is null and the - // nsIScriptObjectPrincipal ownership is either handled by the - // nsCOMPtr or dealt with, or we'll release in the finalize - // hook. - if (glob && NS_FAILED(xpc->InitClasses(mSafeJSContext, glob))) { - glob = nsnull; - } - - } - if (mSafeJSContext && !glob) { - // Destroy the context outside the scope of JSAutoRequest that - // uses the context in its destructor. - JS_DestroyContext(mSafeJSContext); - mSafeJSContext = nsnull; - } - // Save it off so we can destroy it later. - mOwnSafeJSContext = mSafeJSContext; + // After this point either glob is null and the + // nsIScriptObjectPrincipal ownership is either handled by the + // nsCOMPtr or dealt with, or we'll release in the finalize + // hook. + if (glob && NS_FAILED(xpc->InitClasses(mSafeJSContext, glob))) { + glob = nsnull; } } + if (mSafeJSContext && !glob) { + // Destroy the context outside the scope of JSAutoRequest that + // uses the context in its destructor. + JS_DestroyContext(mSafeJSContext); + mSafeJSContext = nsnull; + } - *aSafeJSContext = mSafeJSContext; - return mSafeJSContext ? NS_OK : NS_ERROR_UNEXPECTED; + // Save it off so we can destroy it later. + mOwnSafeJSContext = mSafeJSContext; + + return mSafeJSContext; } /***************************************************************************/ diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index f9d5e622ae3..10725a1e0a1 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -534,9 +534,8 @@ GetContextFromObject(JSObject *obj) // Don't stomp over a running context. XPCJSContextStack* stack = XPCPerThreadData::GetData(nsnull)->GetJSContextStack(); - JSContext* topJSContext; - if (stack && NS_SUCCEEDED(stack->Peek(&topJSContext)) && topJSContext) + if (stack && stack->Peek()) return nsnull; // In order to get a context, we need a context. diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 7fca8a44121..15c8ce81cfc 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -1311,7 +1311,7 @@ public: ~AutoPopJSContext() { if (mCx) - mStack->Pop(nsnull); + mStack->Pop(); } void PushIfNotTop(JSContext *cx) @@ -1319,10 +1319,9 @@ public: NS_ASSERTION(cx, "Null context!"); NS_ASSERTION(!mCx, "This class is only meant to be used once!"); - JSContext *cxTop = nsnull; - mStack->Peek(&cxTop); + JSContext *cxTop = mStack->Peek(); - if (cxTop != cx && NS_SUCCEEDED(mStack->Push(cx))) + if (cxTop != cx && mStack->Push(cx)) mCx = cx; } diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 815766731d7..2e055bb0a70 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 @@ -2463,8 +2463,7 @@ nsXPConnect::UnregisterGCCallback(JSGCCallback func) NS_IMETHODIMP nsXPConnect::GetCount(PRInt32 *aCount) { - if (!aCount) - return NS_ERROR_NULL_POINTER; + MOZ_ASSERT(aCount); XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull); @@ -2473,15 +2472,15 @@ nsXPConnect::GetCount(PRInt32 *aCount) return NS_ERROR_FAILURE; } - return data->GetJSContextStack()->GetCount(aCount); + *aCount = data->GetJSContextStack()->Count(); + return NS_OK; } /* JSContext Peek (); */ NS_IMETHODIMP nsXPConnect::Peek(JSContext * *_retval) { - if (!_retval) - return NS_ERROR_NULL_POINTER; + MOZ_ASSERT(_retval); XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull); @@ -2490,7 +2489,8 @@ nsXPConnect::Peek(JSContext * *_retval) return NS_ERROR_FAILURE; } - return data->GetJSContextStack()->Peek(_retval); + *_retval = data->GetJSContextStack()->Peek(); + return NS_OK; } void @@ -2581,11 +2581,14 @@ nsXPConnect::Pop(JSContext * *_retval) if (!data) { if (_retval) - *_retval = nsnull; + *_retval = NULL; return NS_ERROR_FAILURE; } - return data->GetJSContextStack()->Pop(_retval); + JSContext *cx = data->GetJSContextStack()->Pop(); + if (_retval) + *_retval = cx; + return NS_OK; } /* void Push (in JSContext cx); */ @@ -2598,7 +2601,7 @@ nsXPConnect::Push(JSContext * cx) return NS_ERROR_FAILURE; if (gDebugMode != gDesiredDebugMode && NS_IsMainThread()) { - const nsTArray* stack = data->GetJSContextStack()->GetStack(); + const InfallibleTArray* stack = data->GetJSContextStack()->GetStack(); if (!gDesiredDebugMode) { /* Turn off debug mode immediately, even if JS code is currently running */ CheckForDebugMode(mRuntime->GetJSRuntime()); @@ -2616,7 +2619,7 @@ nsXPConnect::Push(JSContext * cx) } } - return data->GetJSContextStack()->Push(cx); + return data->GetJSContextStack()->Push(cx) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } /* attribute JSContext SafeJSContext; */ @@ -2632,7 +2635,8 @@ nsXPConnect::GetSafeJSContext(JSContext * *aSafeJSContext) return NS_ERROR_FAILURE; } - return data->GetJSContextStack()->GetSafeJSContext(aSafeJSContext); + *aSafeJSContext = data->GetJSContextStack()->GetSafeJSContext(); + return *aSafeJSContext ? NS_OK : NS_ERROR_FAILURE; } nsIPrincipal* diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index b946fc1f9dd..ff7769f3a2c 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3583,21 +3583,36 @@ struct XPCJSContextInfo { class XPCJSContextStack { public: - NS_DECL_NSIJSCONTEXTSTACK - NS_DECL_NSITHREADJSCONTEXTSTACK + XPCJSContextStack() + : mSafeJSContext(NULL) + , mOwnSafeJSContext(NULL) + { } - XPCJSContextStack(); virtual ~XPCJSContextStack(); + uint32_t Count() + { + return mStack.Length(); + } + + JSContext *Peek() + { + return mStack.IsEmpty() ? NULL : mStack[mStack.Length() - 1].cx; + } + + JSContext *Pop(); + bool Push(JSContext *cx); + JSContext *GetSafeJSContext(); + #ifdef DEBUG - JSBool DEBUG_StackHasJSContext(JSContext* aJSContext); + bool DEBUG_StackHasJSContext(JSContext *cx); #endif - const nsTArray* GetStack() + const InfallibleTArray* GetStack() { return &mStack; } private: - nsAutoTArray mStack; + AutoInfallibleTArray mStack; JSContext* mSafeJSContext; JSContext* mOwnSafeJSContext; }; @@ -3615,7 +3630,7 @@ public: NS_DECL_NSIJSCONTEXTSTACKITERATOR private: - const nsTArray *mStack; + const InfallibleTArray *mStack; PRUint32 mPosition; };