Bug 459656 - Implementing nsIThreadJSContextStack in nsXPConnect. r+sr=mrbkap
authorIgor Bukanov <igor@mir2.org>
Tue, 14 Oct 2008 16:16:25 +0200
changeset 20462 e7774e2e7ca98047b6fdb603d52dce0b987f12c3
parent 20461 be961e0dcf1772872ca39fa79bc596633126437a
child 20463 8bfc81a360baab69032ea8a05d6be44e63455476
push idunknown
push userunknown
push dateunknown
bugs459656
milestone1.9.1b2pre
Bug 459656 - Implementing nsIThreadJSContextStack in nsXPConnect. r+sr=mrbkap
caps/include/nsScriptSecurityManager.h
caps/src/nsScriptSecurityManager.cpp
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpcmodule.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcthreadcontext.cpp
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -582,27 +582,27 @@ private:
     DomainPolicy* mDefaultPolicy;
     nsObjectHashtable* mCapabilities;
 
     nsCOMPtr<nsIPrefBranch> mPrefBranch;
     nsCOMPtr<nsISecurityPref> mSecurityPref;
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
     nsCOMPtr<nsIPrincipal> mSystemCertificate;
     nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals;
-    nsCOMPtr<nsIThreadJSContextStack> mJSContextStack;
     PRPackedBool mIsJavaScriptEnabled;
     PRPackedBool mIsMailJavaScriptEnabled;
     PRPackedBool mIsWritingPrefs;
     PRPackedBool mPolicyPrefsChanged;
 #ifdef XPC_IDISPATCH_SUPPORT    
     PRPackedBool mXPCDefaultGrantAll;
     static const char sXPCDefaultGrantAllName[];
 #endif
 
     static PRBool sStrictFileOriginPolicy;
 
     static nsIIOService    *sIOService;
     static nsIXPConnect    *sXPConnect;
+    static nsIThreadJSContextStack* sJSContextStack;
     static nsIStringBundle *sStrBundle;
     static JSRuntime       *sRuntime;
 };
 
 #endif // nsScriptSecurityManager_h__
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -93,16 +93,17 @@
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIChromeRegistry.h"
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nsnull;
 nsIXPConnect    *nsScriptSecurityManager::sXPConnect = nsnull;
+nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
 PRBool nsScriptSecurityManager::sStrictFileOriginPolicy = PR_TRUE;
 
 // Info we need about the JSClasses used by XPConnects wrapped
 // natives, to avoid having to QI to nsIXPConnectWrappedNative all the
 // time when doing security checks.
 static const JSClass *sXPCWrappedNativeJSClass;
@@ -300,40 +301,28 @@ private:
     nsCOMPtr<nsIJSContextStack> mStack;
     JSContext *mContext;
 };
 
 JSContext *
 nsScriptSecurityManager::GetCurrentJSContext()
 {
     // Get JSContext from stack.
-    if (!mJSContextStack)
-    {
-        mJSContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-        if (!mJSContextStack)
-            return nsnull;
-    }
     JSContext *cx;
-    if (NS_FAILED(mJSContextStack->Peek(&cx)))
+    if (NS_FAILED(sJSContextStack->Peek(&cx)))
         return nsnull;
     return cx;
 }
 
 JSContext *
 nsScriptSecurityManager::GetSafeJSContext()
 {
     // Get JSContext from stack.
-    if (!mJSContextStack) {
-        mJSContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-        if (!mJSContextStack)
-            return nsnull;
-    }
-
     JSContext *cx;
-    if (NS_FAILED(mJSContextStack->GetSafeJSContext(&cx)))
+    if (NS_FAILED(sJSContextStack->GetSafeJSContext(&cx)))
         return nsnull;
     return cx;
 }
 
 /* static */
 PRBool
 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
                                              nsIURI* aTargetURI)
@@ -3230,33 +3219,36 @@ nsScriptSecurityManager::nsScriptSecurit
 {
     NS_ASSERTION(sizeof(long) == sizeof(void*), "long and void* have different lengths on this platform. This may cause a security failure.");
     mPrincipals.Init(31);
 }
 
 
 nsresult nsScriptSecurityManager::Init()
 {
+    nsresult rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = CallGetService("@mozilla.org/js/xpc/ContextStack;1", &sJSContextStack);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     JSContext* cx = GetSafeJSContext();
     if (!cx) return NS_ERROR_FAILURE;   // this can happen of xpt loading fails
     
     ::JS_BeginRequest(cx);
     if (sEnabledID == JSVAL_VOID)
         sEnabledID = STRING_TO_JSVAL(::JS_InternString(cx, "enabled"));
     ::JS_EndRequest(cx);
 
-    nsresult rv = InitPrefs();
+    rv = InitPrefs();
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Create our system principal singleton
     nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
@@ -3313,16 +3305,17 @@ nsScriptSecurityManager::Shutdown()
     if (sRuntime) {
         JS_SetRuntimeSecurityCallbacks(sRuntime, NULL);
         sRuntime = nsnull;
     }
     sEnabledID = JSVAL_VOID;
 
     NS_IF_RELEASE(sIOService);
     NS_IF_RELEASE(sXPConnect);
+    NS_IF_RELEASE(sJSContextStack);
     NS_IF_RELEASE(sStrBundle);
 }
 
 nsScriptSecurityManager *
 nsScriptSecurityManager::GetScriptSecurityManager()
 {
     if (!gScriptSecMan)
     {
@@ -3414,17 +3407,17 @@ nsScriptSecurityManager::InitPolicies()
           new nsObjectHashtable(nsnull, nsnull, DeleteCapability, nsnull);
         if (!mCapabilities)
             return NS_ERROR_OUT_OF_MEMORY;
     }
 
     // Get a JS context - we need it to create internalized strings later.
     JSContext* cx = GetSafeJSContext();
     NS_ASSERTION(cx, "failed to get JS context");
-    AutoCxPusher autoPusher(mJSContextStack, cx);
+    AutoCxPusher autoPusher(sJSContextStack, cx);
     rv = InitDomainPolicy(cx, "default", mDefaultPolicy);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsXPIDLCString policyNames;
     rv = mSecurityPref->SecurityGetCharPref("capability.policy.policynames",
                                             getter_Copies(policyNames));
 
     nsXPIDLCString defaultPolicyNames;
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -48,21 +48,23 @@
 #include "nsHashKeys.h"
 #include "jsatom.h"
 #include "jsfun.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "nsThreadUtilsInternal.h"
 #include "dom_quickstubs.h"
 
-NS_IMPL_THREADSAFE_ISUPPORTS4(nsXPConnect,
+NS_IMPL_THREADSAFE_ISUPPORTS6(nsXPConnect,
                               nsIXPConnect,
                               nsISupportsWeakReference,
                               nsIThreadObserver,
-                              nsIJSRuntimeService)
+                              nsIJSRuntimeService,
+                              nsIJSContextStack,
+                              nsIThreadJSContextStack)
 
 nsXPConnect* nsXPConnect::gSelf = nsnull;
 JSBool       nsXPConnect::gOnceAliveNowDead = JS_FALSE;
 PRUint32     nsXPConnect::gReportAllJSExceptions = 0;
 
 // Global cache of the default script security manager (QI'd to
 // nsIScriptSecurityManager)
 nsIScriptSecurityManager *gScriptSecurityManager = nsnull;
@@ -75,27 +77,24 @@ const char XPC_SCRIPT_ERROR_CONTRACTID[]
 const char XPC_ID_CONTRACTID[]            = "@mozilla.org/js/xpc/ID;1";
 const char XPC_XPCONNECT_CONTRACTID[]     = "@mozilla.org/js/xpc/XPConnect;1";
 
 /***************************************************************************/
 
 nsXPConnect::nsXPConnect()
     :   mRuntime(nsnull),
         mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)),
-        mContextStack(nsnull),
         mDefaultSecurityManager(nsnull),
         mDefaultSecurityManagerFlags(0),
         mShuttingDown(JS_FALSE),
         mCycleCollectionContext(nsnull),
         mCycleCollecting(PR_FALSE)
 {
     mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
 
-    CallGetService(XPC_CONTEXT_STACK_CONTRACTID, &mContextStack);
-
     nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
 #ifdef DEBUG_CC
     mJSRoots.ops = nsnull;
 #endif
 
 #ifdef XPC_TOOLS_SUPPORT
   {
     char* filename = PR_GetEnv("MOZILLA_JS_PROFILER_OUTPUT");
@@ -150,17 +149,16 @@ nsXPConnect::~nsXPConnect()
         XPCWrappedNativeScope::SystemIsBeingShutDown(cx);
 
         mRuntime->SystemIsBeingShutDown(cx);
 
         JS_EndRequest(cx);
         JS_DestroyContext(cx);
     }
 
-    NS_IF_RELEASE(mContextStack);
     NS_IF_RELEASE(mDefaultSecurityManager);
 
     gScriptSecurityManager = nsnull;
 
     // shutdown the logging system
     XPC_LOG_FINISH();
 
     delete mRuntime;
@@ -177,18 +175,17 @@ nsXPConnect::GetXPConnect()
     {
         if(gOnceAliveNowDead)
             return nsnull;
         gSelf = new nsXPConnect();
         if(!gSelf)
             return nsnull;
 
         if(!gSelf->mRuntime ||
-           !gSelf->mInterfaceInfoManager ||
-           !gSelf->mContextStack)
+           !gSelf->mInterfaceInfoManager)
         {
             // ctor failed to create an acceptable instance
             delete gSelf;
             gSelf = nsnull;
         }
         else
         {
             // Initial extra ref to keep the singleton alive
@@ -227,32 +224,35 @@ nsXPConnect::ReleaseXPConnectSingleton()
             xpc->mProfiler->Stop();
             xpc->mProfiler->WriteResults(xpc->mProfilerOutputFile);
         }
 #endif
 
 #ifdef DEBUG
         // force a dump of the JavaScript gc heap if JS is still alive
         // if requested through XPC_SHUTDOWN_HEAP_DUMP environment variable
-        XPCCallContext ccx(NATIVE_CALLER);
-        if(ccx.IsValid())
         {
-            const char* dumpName = getenv("XPC_SHUTDOWN_HEAP_DUMP");
-            if(dumpName)
+            // autoscope
+            XPCCallContext ccx(NATIVE_CALLER);
+            if(ccx.IsValid())
             {
-                FILE* dumpFile = (*dumpName == '\0' ||
-                                  strcmp(dumpName, "stdout") == 0)
-                                 ? stdout
-                                 : fopen(dumpName, "w");
-                if(dumpFile)
+                const char* dumpName = getenv("XPC_SHUTDOWN_HEAP_DUMP");
+                if(dumpName)
                 {
-                    JS_DumpHeap(ccx, dumpFile, nsnull, 0, nsnull,
-                                static_cast<size_t>(-1), nsnull);
-                    if(dumpFile != stdout)
-                        fclose(dumpFile);
+                    FILE* dumpFile = (*dumpName == '\0' ||
+                                      strcmp(dumpName, "stdout") == 0)
+                                     ? stdout
+                                     : fopen(dumpName, "w");
+                    if(dumpFile)
+                    {
+                        JS_DumpHeap(ccx, dumpFile, nsnull, 0, nsnull,
+                                    static_cast<size_t>(-1), nsnull);
+                        if(dumpFile != stdout)
+                            fclose(dumpFile);
+                    }
                 }
             }
         }
 #endif
 #ifdef XPC_DUMP_AT_SHUTDOWN
         // NOTE: to see really interesting stuff turn on the prlog stuff.
         // See the comment at the top of xpclog.h to see how to do that.
         xpc->DebugDump(7);
@@ -277,31 +277,16 @@ nsXPConnect::GetInterfaceInfoManager(nsI
         return NS_ERROR_FAILURE;
 
     *iim = xpc->mInterfaceInfoManager;
     NS_IF_ADDREF(*iim);
     return NS_OK;
 }
 
 // static
-nsresult
-nsXPConnect::GetContextStack(nsIThreadJSContextStack** stack,
-                             nsXPConnect* xpc /*= nsnull*/)
-{
-    nsIThreadJSContextStack* temp;
-
-    if(!xpc && !(xpc = GetXPConnect()))
-        return NS_ERROR_FAILURE;
-
-    *stack = temp = xpc->mContextStack;
-    NS_IF_ADDREF(temp);
-    return NS_OK;
-}
-
-// static
 XPCJSRuntime*
 nsXPConnect::GetRuntimeInstance()
 {
     nsXPConnect* xpc = GetXPConnect();
     NS_ASSERTION(xpc, "Must not be called if XPC failed to initialize");
     return xpc->GetRuntime();
 }
 
@@ -1586,17 +1571,17 @@ nsXPConnect::CreateStackFrameLocation(PR
 NS_IMETHODIMP
 nsXPConnect::GetCurrentJSStack(nsIStackFrame * *aCurrentJSStack)
 {
     NS_ASSERTION(aCurrentJSStack, "bad param");
     *aCurrentJSStack = nsnull;
 
     JSContext* cx;
     // is there a current context available?
-    if(mContextStack && NS_SUCCEEDED(mContextStack->Peek(&cx)) && cx)
+    if(NS_SUCCEEDED(Peek(&cx)) && cx)
     {
         nsCOMPtr<nsIStackFrame> stack;
         XPCJSStack::CreateStack(cx, getter_AddRefs(stack));
         if(stack)
         {
             // peel off native frames...
             PRUint32 language;
             nsCOMPtr<nsIStackFrame> caller;
@@ -2038,17 +2023,16 @@ nsXPConnect::DebugDump(PRInt16 depth)
     depth-- ;
     XPC_LOG_ALWAYS(("nsXPConnect @ %x with mRefCnt = %d", this, mRefCnt.get()));
     XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("gSelf @ %x", gSelf));
         XPC_LOG_ALWAYS(("gOnceAliveNowDead is %d", (int)gOnceAliveNowDead));
         XPC_LOG_ALWAYS(("mDefaultSecurityManager @ %x", mDefaultSecurityManager));
         XPC_LOG_ALWAYS(("mDefaultSecurityManagerFlags of %x", mDefaultSecurityManagerFlags));
         XPC_LOG_ALWAYS(("mInterfaceInfoManager @ %x", mInterfaceInfoManager.get()));
-        XPC_LOG_ALWAYS(("mContextStack @ %x", mContextStack));
         if(mRuntime)
         {
             if(depth)
                 mRuntime->DebugDump(depth);
             else
                 XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", mRuntime));
         }
         else
@@ -2113,42 +2097,32 @@ nsXPConnect::DebugDumpObject(nsISupports
 
 /* void debugDumpJSStack (in PRBool showArgs, in PRBool showLocals, in PRBool showThisProps); */
 NS_IMETHODIMP
 nsXPConnect::DebugDumpJSStack(PRBool showArgs,
                               PRBool showLocals,
                               PRBool showThisProps)
 {
     JSContext* cx;
-    nsresult rv;
-    nsCOMPtr<nsIThreadJSContextStack> stack = 
-             do_GetService(XPC_CONTEXT_STACK_CONTRACTID, &rv);
-    if(NS_FAILED(rv) || !stack)
-        printf("failed to get nsIThreadJSContextStack service!\n");
-    else if(NS_FAILED(stack->Peek(&cx)))
+    if(NS_FAILED(Peek(&cx)))
         printf("failed to peek into nsIThreadJSContextStack service!\n");
     else if(!cx)
         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
     else
         xpc_DumpJSStack(cx, showArgs, showLocals, showThisProps);
 
     return NS_OK;
 }
 
 /* void debugDumpEvalInJSStackFrame (in PRUint32 aFrameNumber, in string aSourceText); */
 NS_IMETHODIMP
 nsXPConnect::DebugDumpEvalInJSStackFrame(PRUint32 aFrameNumber, const char *aSourceText)
 {
     JSContext* cx;
-    nsresult rv;
-    nsCOMPtr<nsIThreadJSContextStack> stack = 
-             do_GetService(XPC_CONTEXT_STACK_CONTRACTID, &rv);
-    if(NS_FAILED(rv) || !stack)
-        printf("failed to get nsIThreadJSContextStack service!\n");
-    else if(NS_FAILED(stack->Peek(&cx)))
+    if(NS_FAILED(Peek(&cx)))
         printf("failed to peek into nsIThreadJSContextStack service!\n");
     else if(!cx)
         printf("there is no JSContext on the nsIThreadJSContextStack!\n");
     else
         xpc_DumpEvalInJSStackFrame(cx, aFrameNumber, aSourceText);
 
     return NS_OK;
 }
@@ -2215,26 +2189,24 @@ nsXPConnect::FlagSystemFilenamePrefix(co
 }
 
 NS_IMETHODIMP
 nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, PRBool aMayWait,
                                 PRUint32 aRecursionDepth)
 {
     // Push a null JSContext so that we don't see any script during
     // event processing.
-    NS_ENSURE_STATE(mContextStack);
-    return mContextStack->Push(nsnull);
+    return Push(nsnull);
 }
 
 NS_IMETHODIMP
 nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
                                    PRUint32 aRecursionDepth)
 {
-    NS_ENSURE_STATE(mContextStack);
-    return mContextStack->Pop(nsnull);
+    return Pop(nsnull);
 }
 
 NS_IMETHODIMP
 nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
 {
     NS_NOTREACHED("Why tell us?");
     return NS_ERROR_UNEXPECTED;
 }
@@ -2304,16 +2276,111 @@ nsXPConnect::GetBackstagePass(nsIXPCScri
 #endif
         if(!mBackstagePass)
             return NS_ERROR_OUT_OF_MEMORY;
     }
     NS_ADDREF(*bsp = mBackstagePass);
     return NS_OK;
 }
 
+//  nsIJSContextStack and nsIThreadJSContextStack implementations
+
+/* readonly attribute PRInt32 Count; */
+NS_IMETHODIMP
+nsXPConnect::GetCount(PRInt32 *aCount)
+{
+    if(!aCount)
+        return NS_ERROR_NULL_POINTER;
+
+    XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
+
+    if(!data)
+    {
+        *aCount = 0;
+        return NS_ERROR_FAILURE;
+    }
+
+    return data->GetJSContextStack()->GetCount(aCount);
+}
+
+/* JSContext Peek (); */
+NS_IMETHODIMP
+nsXPConnect::Peek(JSContext * *_retval)
+{
+    if(!_retval)
+        return NS_ERROR_NULL_POINTER;
+
+    XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
+
+    if(!data)
+    {
+        *_retval = nsnull;
+        return NS_ERROR_FAILURE;
+    }
+
+    return data->GetJSContextStack()->Peek(_retval);
+}
+
+/* JSContext Pop (); */
+NS_IMETHODIMP
+nsXPConnect::Pop(JSContext * *_retval)
+{
+    XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
+
+    if(!data)
+    {
+        if(_retval)
+            *_retval = nsnull;
+        return NS_ERROR_FAILURE;
+    }
+
+    return data->GetJSContextStack()->Pop(_retval);
+}
+
+/* void Push (in JSContext cx); */
+NS_IMETHODIMP
+nsXPConnect::Push(JSContext * cx)
+{
+    XPCPerThreadData* data = XPCPerThreadData::GetData(cx);
+
+    if(!data)
+        return NS_ERROR_FAILURE;
+
+    return data->GetJSContextStack()->Push(cx);
+}
+
+/* attribute JSContext SafeJSContext; */
+NS_IMETHODIMP
+nsXPConnect::GetSafeJSContext(JSContext * *aSafeJSContext)
+{
+    NS_ASSERTION(aSafeJSContext, "loser!");
+
+    XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
+
+    if(!data)
+    {
+        *aSafeJSContext = nsnull;
+        return NS_ERROR_FAILURE;
+    }
+
+    return data->GetJSContextStack()->GetSafeJSContext(aSafeJSContext);
+}
+
+/* attribute JSContext SafeJSContext; */
+NS_IMETHODIMP
+nsXPConnect::SetSafeJSContext(JSContext * aSafeJSContext)
+{
+    XPCPerThreadData* data = XPCPerThreadData::GetData(aSafeJSContext);
+
+    if(!data)
+        return NS_ERROR_FAILURE;
+
+    return data->GetJSContextStack()->SetSafeJSContext(aSafeJSContext);
+}
+
 /* These are here to be callable from a debugger */
 JS_BEGIN_EXTERN_C
 JS_EXPORT_API(void) DumpJSStack()
 {
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if(NS_SUCCEEDED(rv) && xpc)
         xpc->DebugDumpJSStack(PR_TRUE, PR_TRUE, PR_FALSE);
--- a/js/src/xpconnect/src/xpcmodule.cpp
+++ b/js/src/xpconnect/src/xpcmodule.cpp
@@ -61,34 +61,33 @@ NS_DECL_CLASSINFO(XPCVariant)
 #define SCRIPTABLE_INTERFACES_CID \
     {0xfe4f7592, 0xc1fc, 0x4662, \
       { 0xac, 0x83, 0x53, 0x88, 0x41, 0x31, 0x88, 0x3 } }
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSID)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCException)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCJSContextStackIterator)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIXPConnect, nsXPConnect::GetSingleton)
-NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIJSContextStack, nsXPCThreadJSContextStackImpl::GetSingleton)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPCComponents_Interfaces)
 
 #ifdef XPC_IDISPATCH_SUPPORT
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIDispatchSupport, nsDispatchSupport::GetSingleton)
 #endif
 
 NS_DECL_CLASSINFO(nsXPCException)
 
 #ifdef XPCONNECT_STANDALONE
 #define NO_SUBSCRIPT_LOADER
 #endif
 
 static const nsModuleComponentInfo components[] = {
   {nsnull, NS_JS_ID_CID,                         XPC_ID_CONTRACTID,            nsJSIDConstructor             },
   {nsnull, NS_XPCONNECT_CID,                     XPC_XPCONNECT_CONTRACTID,     nsIXPConnectConstructor       },
-  {nsnull, NS_XPC_THREAD_JSCONTEXT_STACK_CID,    XPC_CONTEXT_STACK_CONTRACTID, nsIJSContextStackConstructor  },
+  {nsnull, NS_XPC_THREAD_JSCONTEXT_STACK_CID,    XPC_CONTEXT_STACK_CONTRACTID, nsIXPConnectConstructor  },
   {nsnull, NS_XPCEXCEPTION_CID,                  XPC_EXCEPTION_CONTRACTID,     nsXPCExceptionConstructor, nsnull, nsnull, nsnull, NS_CI_INTERFACE_GETTER_NAME(nsXPCException), nsnull, &NS_CLASSINFO_NAME(nsXPCException), nsIClassInfo::DOM_OBJECT },
   {nsnull, NS_JS_RUNTIME_SERVICE_CID,            XPC_RUNTIME_CONTRACTID,       nsIXPConnectConstructor},
   {NS_SCRIPTERROR_CLASSNAME, NS_SCRIPTERROR_CID, NS_SCRIPTERROR_CONTRACTID,    nsScriptErrorConstructor      },
   {nsnull, SCRIPTABLE_INTERFACES_CID,            NS_SCRIPTABLE_INTERFACES_CONTRACTID,        nsXPCComponents_InterfacesConstructor, 0, 0, 0, 0, 0, 0, nsIClassInfo::THREADSAFE },
   {nsnull, XPCVARIANT_CID,                       XPCVARIANT_CONTRACTID,        nsnull, nsnull, nsnull, nsnull, NS_CI_INTERFACE_GETTER_NAME(XPCVariant), nsnull, &NS_CLASSINFO_NAME(XPCVariant)},
   {nsnull, NS_XPC_JSCONTEXT_STACK_ITERATOR_CID,  XPC_JSCONTEXT_STACK_ITERATOR_CONTRACTID, nsXPCJSContextStackIteratorConstructor }
 
 #ifdef MOZ_JSLOADER
@@ -109,31 +108,29 @@ static const nsModuleComponentInfo compo
 
 static nsresult
 xpcModuleCtor(nsIModule* self)
 {
     nsXPConnect::InitStatics();
     nsXPCException::InitStatics();
     XPCWrappedNativeScope::InitStatics();
     XPCPerThreadData::InitStatics();
-    nsXPCThreadJSContextStackImpl::InitStatics();
 
 #ifdef XPC_IDISPATCH_SUPPORT
     XPCIDispatchExtension::InitStatics();
 #endif
 
     return NS_OK;
 }
 
 static void
 xpcModuleDtor(nsIModule* self)
 {
     // Release our singletons
     nsXPConnect::ReleaseXPConnectSingleton();
-    nsXPCThreadJSContextStackImpl::FreeSingleton();
     xpc_DestroyJSxIDClassObjects();
 #ifdef XPC_IDISPATCH_SUPPORT
     nsDispatchSupport::FreeSingleton();
     XPCIDispatchClassInfo::FreeSingleton();
 #endif
 }
 
 NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(xpconnect, components, xpcModuleCtor, xpcModuleDtor)
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -441,45 +441,48 @@ private:
 
 const PRBool OBJ_IS_GLOBAL = PR_TRUE;
 const PRBool OBJ_IS_NOT_GLOBAL = PR_FALSE;
 
 #define NS_JS_RUNTIME_SERVICE_CID \
 {0xb5e65b52, 0x1dd1, 0x11b2, \
     { 0xae, 0x8f, 0xf0, 0x92, 0x8e, 0xd8, 0x84, 0x82 }}
 
+#define NS_XPC_THREAD_JSCONTEXT_STACK_CID  \
+{ 0xff8c4d10, 0x3194, 0x11d3, \
+    { 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
+
 class nsXPConnect : public nsIXPConnect,
                     public nsIThreadObserver,
                     public nsSupportsWeakReference,
                     public nsCycleCollectionJSRuntime,
                     public nsCycleCollectionParticipant,
-                    public nsIJSRuntimeService
+                    public nsIJSRuntimeService,
+                    public nsIThreadJSContextStack
 {
 public:
     // all the interface method declarations...
     NS_DECL_ISUPPORTS
     NS_DECL_NSIXPCONNECT
     NS_DECL_NSITHREADOBSERVER
     NS_DECL_NSIJSRUNTIMESERVICE
+    NS_DECL_NSIJSCONTEXTSTACK
+    NS_DECL_NSITHREADJSCONTEXTSTACK
 
     // non-interface implementation
 public:
     // These get non-addref'd pointers
     static nsXPConnect*  GetXPConnect();
     static XPCJSRuntime* GetRuntimeInstance();
     XPCJSRuntime* GetRuntime() {return mRuntime;}
 
     // Gets addref'd pointer
     static nsresult GetInterfaceInfoManager(nsIInterfaceInfoSuperManager** iim,
                                             nsXPConnect* xpc = nsnull);
 
-    // Gets addref'd pointer
-    static nsresult GetContextStack(nsIThreadJSContextStack** stack,
-                                    nsXPConnect* xpc = nsnull);
-
     static JSBool IsISupportsDescendant(nsIInterfaceInfo* info);
 
     nsIXPCSecurityManager* GetDefaultSecurityManager() const
         {return mDefaultSecurityManager;}
 
     PRUint16 GetDefaultSecurityManagerFlags() const
         {return mDefaultSecurityManagerFlags;}
 
@@ -554,17 +557,16 @@ private:
 
 private:
     // Singleton instance
     static nsXPConnect*      gSelf;
     static JSBool            gOnceAliveNowDead;
 
     XPCJSRuntime*            mRuntime;
     nsCOMPtr<nsIInterfaceInfoSuperManager> mInterfaceInfoManager;
-    nsIThreadJSContextStack* mContextStack;
     nsIXPCSecurityManager*   mDefaultSecurityManager;
     PRUint16                 mDefaultSecurityManagerFlags;
     JSBool                   mShuttingDown;
     XPCCallContext*          mCycleCollectionContext;
 #ifdef DEBUG_CC
     nsAutoPtr<XPCCallContext> mExplainCycleCollectionContext;
     PLDHashTable             mJSRoots;
 #endif
@@ -3223,50 +3225,16 @@ private:
     // Cached value of cx->thread on the main thread. 
     static void *sMainJSThread;
 
     // Cached per thread data for the main thread. Only safe to access
     // if cx->thread == sMainJSThread.
     static XPCPerThreadData *sMainThreadData;
 };
 
-/**************************************************************/
-
-#define NS_XPC_THREAD_JSCONTEXT_STACK_CID  \
-{ 0xff8c4d10, 0x3194, 0x11d3, \
-    { 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
-
-class nsXPCThreadJSContextStackImpl : public nsIThreadJSContextStack,
-                                      public nsSupportsWeakReference
-{
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIJSCONTEXTSTACK
-    NS_DECL_NSITHREADJSCONTEXTSTACK
-
-    // This returns and AddRef'd pointer. It does not do this with an out param
-    // only because this form  is required by generic module macro:
-    // NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
-    static nsXPCThreadJSContextStackImpl* GetSingleton();
-
-    static void InitStatics() { gXPCThreadJSContextStack = nsnull; }
-    static void FreeSingleton();
-
-    nsXPCThreadJSContextStackImpl();
-    virtual ~nsXPCThreadJSContextStackImpl();
-
-private:
-    XPCJSContextStack* GetStackForCurrentThread(JSContext *cx = nsnull)
-        {XPCPerThreadData* data = XPCPerThreadData::GetData(cx);
-         return data ? data->GetJSContextStack() : nsnull;}
-
-    static nsXPCThreadJSContextStackImpl* gXPCThreadJSContextStack;
-    friend class nsXPCJSContextStackIterator;
-};
-
 /***************************************************************************/
 #ifndef XPCONNECT_STANDALONE
 #include "nsIScriptSecurityManager.h"
 
 class BackstagePass : public nsIScriptObjectPrincipal,
                       public nsIXPCScriptable,
                       public nsIClassInfo
 {
--- a/js/src/xpconnect/src/xpcthreadcontext.cpp
+++ b/js/src/xpconnect/src/xpcthreadcontext.cpp
@@ -268,166 +268,16 @@ XPCJSContextStack::SetSafeJSContext(JSCo
     }
 
     mSafeJSContext = aSafeJSContext;
     return NS_OK;
 }
 
 /***************************************************************************/
 
-/*
- * nsXPCThreadJSContextStackImpl holds state that we don't want to lose!
- *
- * The plan is that once created nsXPCThreadJSContextStackImpl never goes
- * away until FreeSingleton is called. We do an intentional extra addref at
- * construction to keep it around even if no one is using it.
- */
-
-NS_IMPL_THREADSAFE_ISUPPORTS3(nsXPCThreadJSContextStackImpl,
-                              nsIThreadJSContextStack,
-                              nsIJSContextStack,
-                              nsISupportsWeakReference)
-
-nsXPCThreadJSContextStackImpl*
-nsXPCThreadJSContextStackImpl::gXPCThreadJSContextStack = nsnull;
-
-nsXPCThreadJSContextStackImpl::nsXPCThreadJSContextStackImpl()
-{
-}
-
-nsXPCThreadJSContextStackImpl::~nsXPCThreadJSContextStackImpl()
-{
-    gXPCThreadJSContextStack = nsnull;
-}
-
-//static
-nsXPCThreadJSContextStackImpl*
-nsXPCThreadJSContextStackImpl::GetSingleton()
-{
-    if(!gXPCThreadJSContextStack)
-    {
-        gXPCThreadJSContextStack = new nsXPCThreadJSContextStackImpl();
-        // hold an extra reference to lock it down
-        NS_IF_ADDREF(gXPCThreadJSContextStack);
-    }
-    NS_IF_ADDREF(gXPCThreadJSContextStack);
-
-    return gXPCThreadJSContextStack;
-}
-
-void
-nsXPCThreadJSContextStackImpl::FreeSingleton()
-{
-    nsXPCThreadJSContextStackImpl* tcs = gXPCThreadJSContextStack;
-    if(tcs)
-    {
-        nsrefcnt cnt;
-        NS_RELEASE2(tcs, cnt);
-#ifdef XPC_DUMP_AT_SHUTDOWN
-        if(0 != cnt)
-            printf("*** dangling reference to nsXPCThreadJSContextStackImpl: refcnt=%d\n", cnt);
-#endif
-    }
-}
-
-/* readonly attribute PRInt32 Count; */
-NS_IMETHODIMP
-nsXPCThreadJSContextStackImpl::GetCount(PRInt32 *aCount)
-{
-    if(!aCount)
-        return NS_ERROR_NULL_POINTER;
-
-    XPCJSContextStack* myStack = GetStackForCurrentThread();
-
-    if(!myStack)
-    {
-        *aCount = 0;
-        return NS_ERROR_FAILURE;
-    }
-
-    return myStack->GetCount(aCount);
-}
-
-/* JSContext Peek (); */
-NS_IMETHODIMP
-nsXPCThreadJSContextStackImpl::Peek(JSContext * *_retval)
-{
-    if(!_retval)
-        return NS_ERROR_NULL_POINTER;
-
-    XPCJSContextStack* myStack = GetStackForCurrentThread();
-
-    if(!myStack)
-    {
-        *_retval = nsnull;
-        return NS_ERROR_FAILURE;
-    }
-
-    return myStack->Peek(_retval);
-}
-
-/* JSContext Pop (); */
-NS_IMETHODIMP
-nsXPCThreadJSContextStackImpl::Pop(JSContext * *_retval)
-{
-    XPCJSContextStack* myStack = GetStackForCurrentThread();
-
-    if(!myStack)
-    {
-        if(_retval)
-            *_retval = nsnull;
-        return NS_ERROR_FAILURE;
-    }
-
-    return myStack->Pop(_retval);
-}
-
-/* void Push (in JSContext cx); */
-NS_IMETHODIMP
-nsXPCThreadJSContextStackImpl::Push(JSContext * cx)
-{
-    XPCJSContextStack* myStack = GetStackForCurrentThread(cx);
-
-    if(!myStack)
-        return NS_ERROR_FAILURE;
-
-    return myStack->Push(cx);
-}
-
-/* readonly attribute JSContext SafeJSContext; */
-NS_IMETHODIMP
-nsXPCThreadJSContextStackImpl::GetSafeJSContext(JSContext * *aSafeJSContext)
-{
-    NS_ASSERTION(aSafeJSContext, "loser!");
-
-    XPCJSContextStack* myStack = GetStackForCurrentThread();
-
-    if(!myStack)
-    {
-        *aSafeJSContext = nsnull;
-        return NS_ERROR_FAILURE;
-    }
-
-    return myStack->GetSafeJSContext(aSafeJSContext);
-}
-
-
-NS_IMETHODIMP
-nsXPCThreadJSContextStackImpl::SetSafeJSContext(JSContext * aSafeJSContext)
-{
-    XPCJSContextStack* myStack = GetStackForCurrentThread(aSafeJSContext);
-
-    if(!myStack)
-        return NS_ERROR_FAILURE;
-
-    return myStack->SetSafeJSContext(aSafeJSContext);
-}
-
-/***************************************************************************/
-
 PRUintn           XPCPerThreadData::gTLSIndex       = BAD_TLS_INDEX;
 PRLock*           XPCPerThreadData::gLock           = nsnull;
 XPCPerThreadData* XPCPerThreadData::gThreads        = nsnull;
 XPCPerThreadData *XPCPerThreadData::sMainThreadData = nsnull;
 void *            XPCPerThreadData::sMainJSThread   = nsnull;
 
 static jsuword
 GetThreadStackLimit()
@@ -668,23 +518,22 @@ XPCPerThreadData::IterateThreads(XPCPerT
     return *iteratorp;
 }
 
 NS_IMPL_ISUPPORTS1(nsXPCJSContextStackIterator, nsIJSContextStackIterator)
 
 NS_IMETHODIMP
 nsXPCJSContextStackIterator::Reset(nsIJSContextStack *aStack)
 {
-    // XXX This is pretty ugly.
-    nsXPCThreadJSContextStackImpl *impl =
-        static_cast<nsXPCThreadJSContextStackImpl*>(aStack);
-    XPCJSContextStack *stack = impl->GetStackForCurrentThread();
-    if(!stack)
+    NS_ASSERTION(aStack == nsXPConnect::GetXPConnect(),
+                 "aStack must be implemented by XPConnect singleton");
+    XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
+    if(!data)
         return NS_ERROR_FAILURE;
-    mStack = stack->GetStack();
+    mStack = data->GetJSContextStack()->GetStack();
     if(mStack->IsEmpty())
         mStack = nsnull;
     else
         mPosition = mStack->Length() - 1;
 
     return NS_OK;
 }