Bug 408539 - Storing XPCContext inside JSContext
authorIgor Bukanov <igor@mir2.org>
Sat, 11 Oct 2008 19:35:39 +0200
changeset 20312 09fcb1bab6ebb3393ab648c608b855d0c646d2b2
parent 20311 b4aef95eab7312c8dd38c0e01be4e7c9d90daa32
child 20313 16151b2231261ad5c80e292752fcd2c7043bbaf3
push idunknown
push userunknown
push dateunknown
bugs408539
milestone1.9.1b2pre
Bug 408539 - Storing XPCContext inside JSContext
dom/src/base/nsJSEnvironment.cpp
extensions/jssh/nsJSSh.cpp
js/src/jscntxt.h
js/src/xpconnect/idl/nsIXPConnect.idl
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
js/src/xpconnect/src/XPCIDispatchExtension.cpp
js/src/xpconnect/src/XPCNativeWrapper.cpp
js/src/xpconnect/src/XPCWrapper.cpp
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpccallcontext.cpp
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpccontext.cpp
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcexception.cpp
js/src/xpconnect/src/xpcforwards.h
js/src/xpconnect/src/xpcinlines.h
js/src/xpconnect/src/xpcjsid.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcmaps.cpp
js/src/xpconnect/src/xpcmaps.h
js/src/xpconnect/src/xpcmodule.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcruntimesvc.cpp
js/src/xpconnect/src/xpcthreadcontext.cpp
js/src/xpconnect/src/xpcvariant.cpp
js/src/xpconnect/src/xpcwrappedjs.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativeinfo.cpp
js/src/xpconnect/src/xpcwrappednativescope.cpp
js/src/xpconnect/tests/TestXPC.cpp
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -1197,21 +1197,16 @@ nsJSContext::JSOptionChangedCallback(con
 
 nsJSContext::nsJSContext(JSRuntime *aRuntime) : mGCOnDestruction(PR_TRUE)
 {
 
   ++sContextCount;
 
   mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS | JSOPTION_ANONFUNFIX;
 
-  // Let xpconnect resync its JSContext tracker. We do this before creating
-  // a new JSContext just in case the heap manager recycles the JSContext
-  // struct.
-  nsContentUtils::XPConnect()->SyncJSContexts();
-
   mContext = ::JS_NewContext(aRuntime, gStackSize);
   if (mContext) {
     ::JS_SetContextPrivate(mContext, static_cast<nsIScriptContext *>(this));
 
     // Make sure the new context gets the default context options
     ::JS_SetOptions(mContext, mDefaultJSOptions);
 
     // Watch for the JS boolean options
--- a/extensions/jssh/nsJSSh.cpp
+++ b/extensions/jssh/nsJSSh.cpp
@@ -575,21 +575,16 @@ NS_IMETHODIMP nsJSSh::Init()
   }
   
   nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
   if (!xpc) {
     NS_ERROR("failed to get xpconnect service");
     return NS_ERROR_FAILURE;
   }
 
-  // Let xpconnect resync its JSContext tracker. We do this before creating
-  // a new JSContext just in case the heap manager recycles the JSContext
-  // struct.
-  xpc->SyncJSContexts();
-  
   nsCOMPtr<nsIJSRuntimeService> rtsvc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
   // get the JSRuntime from the runtime svc
   if (!rtsvc) {
     NS_ERROR("failed to get nsJSRuntimeService");
     return NS_ERROR_FAILURE;
   }
   
   JSRuntime *rt = nsnull;
@@ -662,17 +657,16 @@ NS_IMETHODIMP nsJSSh::Cleanup()
     if (mContextObj != mGlobal)
       JS_RemoveRoot(mJSContext, &(mContextObj));
 
     JS_ClearScope(mJSContext, mGlobal);
     JS_GC(mJSContext);
   }
 
   JS_DestroyContext(mJSContext);
-  xpc->SyncJSContexts();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsJSSh::ExecuteBuffer()
 {
 #ifdef DEBUG
 //     nsCOMPtr<nsIThread> thread;
 //     nsIThread::GetCurrent(getter_AddRefs(thread));
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -333,17 +333,17 @@ struct JSRuntime {
 
     /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
     JSDebugHooks        globalDebugHooks;
 
     /* More debugging state, see jsdbgapi.c. */
     JSCList             trapList;
     JSCList             watchPointList;
 
-    /* Client opaque pointer */
+    /* Client opaque pointers */
     void                *data;
 
 #ifdef JS_THREADSAFE
     /* These combine to interlock the GC and new requests. */
     PRLock              *gcLock;
     PRCondVar           *gcDone;
     PRCondVar           *requestDone;
     uint32              requestCount;
@@ -846,18 +846,19 @@ struct JSContext {
      */
     uint32              operationCallbackIsSet :    1;
     uint32              operationLimit         :    31;
     JSOperationCallback operationCallback;
 
     /* Interpreter activation count. */
     uintN               interpLevel;
 
-    /* Client opaque pointer */
+    /* Client opaque pointers. */
     void                *data;
+    void                *data2;
 
     /* GC and thread-safe state. */
     JSStackFrame        *dormantFrameChain; /* dormant stack frame to scan */
 #ifdef JS_THREADSAFE
     JSThread            *thread;
     jsrefcount          requestDepth;
     /* Same as requestDepth but ignoring JS_SuspendRequest/JS_ResumeRequest */
     jsrefcount          outstandingRequests;
--- a/js/src/xpconnect/idl/nsIXPConnect.idl
+++ b/js/src/xpconnect/idl/nsIXPConnect.idl
@@ -525,21 +525,17 @@ interface nsIXPConnect : nsISupports
     nsIStackFrame
     createStackFrameLocation(in PRUint32       aLanguage,
                              in string         aFilename,
                              in string         aFunctionName,
                              in PRInt32        aLineNumber,
                              in nsIStackFrame  aCaller);
 
     /**
-    * XPConnect builds internal objects that parallel, and are one-to-one with,
-    * the JSContexts in the JSRuntime. It builds these objects as needed.
-    * This method tells XPConnect to resynchronize its representations with the
-    * list of JSContexts currently 'alive' in the JSRuntime. This allows it
-    * to cleanup any representations of JSContexts that are no longer valid.
+    * Deprecated do-nothing function.
     */
     void syncJSContexts();
 
     readonly attribute nsIStackFrame                CurrentJSStack;
     readonly attribute nsAXPCNativeCallContextPtr   CurrentNativeCallContext;
     /* pass nsnull to clear pending exception */
              attribute nsIException                 PendingException;
 
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -1298,19 +1298,25 @@ nsXPCFunctionThisTranslator::TranslateTh
     *_retval = aInitialThis;
     *aHideFirstParamFromJS = JS_FALSE;
     *aIIDOfResult = nsnull;
     return NS_OK;
 }
 
 #endif
 
+// ContextCallback calls are chained
+static JSContextCallback gOldJSContextCallback;
+
 static JSBool
 ContextCallback(JSContext *cx, uintN contextOp)
 {
+    if (gOldJSContextCallback && !gOldJSContextCallback(cx, contextOp))
+        return JS_FALSE;
+
     if (contextOp == JSCONTEXT_NEW) {
         JS_SetErrorReporter(cx, my_ErrorReporter);
         JS_SetVersion(cx, JSVERSION_LATEST);
     }
     return JS_TRUE;
 }
 
 int
@@ -1352,17 +1358,17 @@ main(int argc, char **argv, char **envp)
             return 1;
         }
     
         if (NS_FAILED(rtsvc->GetRuntime(&rt)) || !rt) {
             printf("failed to get JSRuntime from nsJSRuntimeService!\n");
             return 1;
         }
 
-        JS_SetContextCallback(rt, ContextCallback);
+        gOldJSContextCallback = JS_SetContextCallback(rt, ContextCallback);
 
         cx = JS_NewContext(rt, 8192);
         if (!cx) {
             printf("JS_NewContext failed!\n");
             return 1;
         }
 
         nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID());
@@ -1475,17 +1481,16 @@ main(int argc, char **argv, char **envp)
         JS_ClearScope(cx, glob);
         JS_GC(cx);
         JSContext *oldcx;
         cxstack->Pop(&oldcx);
         NS_ASSERTION(oldcx == cx, "JS thread context push/pop mismatch");
         cxstack = nsnull;
         JS_GC(cx);
         JS_DestroyContext(cx);
-        xpc->SyncJSContexts();
     } // this scopes the nsCOMPtrs
     // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
     rv = NS_ShutdownXPCOM( NULL );
     NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
 
 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
     // test of late call and release (see above)
     JSContext* bogusCX;
--- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
+++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
@@ -182,17 +182,17 @@ GetWrappedObject(JSContext *cx, JSObject
   return JSVAL_TO_OBJECT(v);
 }
 
 JSBool
 XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
                      XPCWrappedNativeScope *newScope)
 {
   typedef WrappedNative2WrapperMap::Link Link;
-  XPCJSRuntime *rt = nsXPConnect::GetRuntime();
+  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
   WrappedNative2WrapperMap *map = innerObj->GetScope()->GetWrapperMap();
   Link *link;
 
   { // Scoped lock
     XPCAutoLock al(rt->GetMapLock());
     link = map->FindLink(innerObj->GetFlatJSObject());
   }
 
@@ -466,17 +466,17 @@ XPC_XOW_WrapObject(JSContext *cx, JSObje
   XPCWrappedNative *wn;
   if (!JSVAL_IS_OBJECT(*vp) ||
       !(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
       STOBJ_GET_CLASS(wrappedObj) == &sXPC_XOW_JSClass.base ||
       !(wn = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, wrappedObj))) {
     return JS_TRUE;
   }
 
-  XPCJSRuntime *rt = nsXPConnect::GetRuntime();
+  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
   XPCCallContext ccx(NATIVE_CALLER, cx);
   NS_ENSURE_TRUE(ccx.IsValid(), JS_FALSE);
 
   // The parent must be the inner global object for its scope.
   parent = JS_GetGlobalForObject(cx, parent);
   JSClass *clasp = STOBJ_GET_CLASS(parent);
   if (clasp->flags & JSCLASS_IS_EXTENDED) {
     JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp);
--- a/js/src/xpconnect/src/XPCIDispatchExtension.cpp
+++ b/js/src/xpconnect/src/XPCIDispatchExtension.cpp
@@ -196,19 +196,19 @@ public:
                         JSNative aCall);
 private:
     XPCJSRuntime * m_Runtime;
     JSContext * m_JSContext;
 };
 
 inline
 xpcFunctionDefiner::xpcFunctionDefiner(JSContext * aJSContext) : 
-    m_Runtime(nsXPConnect::GetRuntime()), m_JSContext(aJSContext)
+    m_Runtime(nsXPConnect::GetRuntimeInstance()), m_JSContext(aJSContext)
 {
-    NS_ASSERTION(m_Runtime, "nsXPConnect::GetRuntime() returned null");
+    NS_ASSERTION(m_Runtime, "nsXPConnect::GetRuntimeInstance() returned null");
     NS_ASSERTION(aJSContext, "xpcFunctionDefiner constructor passed a null context");
 }
 
 inline
 JSFunction * xpcFunctionDefiner::Define(JSObject * globalObject,
                                         uintN aNameIndex, JSNative aCall)
 {
     return JS_DefineFunction(m_JSContext, globalObject,
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -655,17 +655,17 @@ XPC_NW_Convert(JSContext *cx, JSObject *
   return JS_TRUE;
 }
 
 static void
 XPC_NW_Finalize(JSContext *cx, JSObject *obj)
 {
   // We must not use obj's private data here since it's likely that it
   // has already been finalized.
-  XPCJSRuntime *rt = nsXPConnect::GetRuntime();
+  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
 
   {
     // scoped lock
     XPCAutoLock lock(rt->GetMapLock());
     rt->GetExplicitNativeWrapperMap()->Remove(obj);
   }
 }
 
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -734,19 +734,17 @@ XPCWrapper::GetOrSetNativeProperty(JSCon
 // static
 JSBool
 XPCWrapper::NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative,
                            uintN argc, jsval *argv, jsval *rval,
                            JSBool isNativeWrapper)
 {
   // Check whether toString was overridden in any object along
   // the wrapped native's object's prototype chain.
-  XPCJSRuntime *rt = nsXPConnect::GetRuntime();
-  if (!rt)
-    return JS_FALSE;
+  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
 
   jsid id = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING);
   jsval idAsVal;
   if (!::JS_IdToValue(cx, id, &idAsVal)) {
     return JS_FALSE;
   }
 
   // Someone is trying to call toString on our wrapped object.
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -48,20 +48,21 @@
 #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_ISUPPORTS3(nsXPConnect,
+NS_IMPL_THREADSAFE_ISUPPORTS4(nsXPConnect,
                               nsIXPConnect,
                               nsISupportsWeakReference,
-                              nsIThreadObserver)
+                              nsIThreadObserver,
+                              nsIJSRuntimeService)
 
 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;
@@ -81,19 +82,17 @@ nsXPConnect::nsXPConnect()
         mInterfaceInfoManager(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)),
         mContextStack(nsnull),
         mDefaultSecurityManager(nsnull),
         mDefaultSecurityManagerFlags(0),
         mShuttingDown(JS_FALSE),
         mCycleCollectionContext(nsnull),
         mCycleCollecting(PR_FALSE)
 {
-    // Ignore the result. If the runtime service is not ready to rumble
-    // then we'll set this up later as needed.
-    CreateRuntime();
+    mRuntime = XPCJSRuntime::newXPCJSRuntime(this);
 
     CallGetService(XPC_CONTEXT_STACK_CONTRACTID, &mContextStack);
 
     nsCycleCollector_registerRuntime(nsIProgrammingLanguage::JAVASCRIPT, this);
 #ifdef DEBUG_CC
     mJSRoots.ops = nsnull;
 #endif
 
@@ -177,17 +176,18 @@ nsXPConnect::GetXPConnect()
     if(!gSelf)
     {
         if(gOnceAliveNowDead)
             return nsnull;
         gSelf = new nsXPConnect();
         if(!gSelf)
             return nsnull;
 
-        if(!gSelf->mInterfaceInfoManager ||
+        if(!gSelf->mRuntime ||
+           !gSelf->mInterfaceInfoManager ||
            !gSelf->mContextStack)
         {
             // ctor failed to create an acceptable instance
             delete gSelf;
             gSelf = nsnull;
         }
         else
         {
@@ -293,74 +293,33 @@ nsXPConnect::GetContextStack(nsIThreadJS
 
     *stack = temp = xpc->mContextStack;
     NS_IF_ADDREF(temp);
     return NS_OK;
 }
 
 // static
 XPCJSRuntime*
-nsXPConnect::GetRuntime(nsXPConnect* xpc /*= nsnull*/)
-{
-    if(!xpc && !(xpc = GetXPConnect()))
-        return nsnull;
-
-    return xpc->EnsureRuntime() ? xpc->mRuntime : nsnull;
-}
-
-// static 
-nsIJSRuntimeService* 
-nsXPConnect::GetJSRuntimeService(nsXPConnect* xpc /* = nsnull */)
+nsXPConnect::GetRuntimeInstance()
 {
-    XPCJSRuntime* rt = GetRuntime(xpc); 
-    return rt ? rt->GetJSRuntimeService() : nsnull;
-}
-
-// static
-XPCContext*
-nsXPConnect::GetContext(JSContext* cx, nsXPConnect* xpc /*= nsnull*/)
-{
-    NS_PRECONDITION(cx,"bad param");
-
-    XPCJSRuntime* rt = GetRuntime(xpc);
-    if(!rt)
-        return nsnull;
-
-    if(rt->GetJSRuntime() != JS_GetRuntime(cx))
-    {
-        NS_WARNING("XPConnect was passed aJSContext from a foreign JSRuntime!");
-        return nsnull;
-    }
-    return rt->GetXPCContext(cx);
+    nsXPConnect* xpc = GetXPConnect();
+    NS_ASSERTION(xpc, "Must not be called if XPC failed to initialize");
+    return xpc->GetRuntime();
 }
 
 // static
 JSBool
 nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info)
 {
     PRBool found = PR_FALSE;
     if(info)
         info->HasAncestor(&NS_GET_IID(nsISupports), &found);
     return found;
 }
 
-JSBool
-nsXPConnect::CreateRuntime()
-{
-    NS_ASSERTION(!mRuntime,"CreateRuntime called but mRuntime already init'd");
-    nsresult rv;
-    nsCOMPtr<nsIJSRuntimeService> rtsvc = 
-             do_GetService(XPC_RUNTIME_CONTRACTID, &rv);
-    if(NS_SUCCEEDED(rv) && rtsvc)
-    {
-        mRuntime = XPCJSRuntime::newXPCJSRuntime(this, rtsvc);
-    }
-    return nsnull != mRuntime;
-}
-
 /***************************************************************************/
 
 typedef PRBool (*InfoTester)(nsIInterfaceInfoManager* manager, const void* data,
                              nsIInterfaceInfo** info);
 
 static PRBool IIDTester(nsIInterfaceInfoManager* manager, const void* data,
                         nsIInterfaceInfo** info)
 {
@@ -438,33 +397,33 @@ XPCCycleCollectGCCallback(JSContext *cx,
             NS_ASSERTION(!gInCollection, "Recursing?");
 
             gDidCollection = PR_TRUE;
             gInCollection = nsCycleCollector_beginCollection();
         }
 
         // Mark JS objects that are held by XPCOM objects that are in cycles
         // that will not be collected.
-        nsXPConnect::GetRuntime()->
+        nsXPConnect::GetRuntimeInstance()->
             TraceXPConnectRoots(cx->runtime->gcMarkingTracer);
     }
     else if(status == JSGC_END)
     {
         if(gInCollection)
         {
             gInCollection = PR_FALSE;
             gCollected = nsCycleCollector_finishCollection();
         }
-        nsXPConnect::GetRuntime()->RestoreContextGlobals();
+        nsXPConnect::GetRuntimeInstance()->RestoreContextGlobals();
     }
 
     PRBool ok = gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE;
 
     if(status == JSGC_BEGIN)
-        nsXPConnect::GetRuntime()->UnsetContextGlobals();
+        nsXPConnect::GetRuntimeInstance()->UnsetContextGlobals();
 
     return ok;
 }
 
 PRBool
 nsXPConnect::Collect()
 {
     // We're dividing JS objects into 2 categories:
@@ -601,17 +560,17 @@ nsXPConnect::BeginCycleCollection(nsCycl
         // collection identical for DEBUG_CC and non-DEBUG_CC builds.
         if(!PL_DHashTableInit(&mJSRoots, PL_DHashGetStubOps(), nsnull,
                               sizeof(PLDHashEntryStub), PL_DHASH_MIN_SIZE)) {
             mJSRoots.ops = nsnull;
 
             return NS_ERROR_OUT_OF_MEMORY;
         }
 
-        nsXPConnect::GetRuntime()->UnsetContextGlobals();
+        GetRuntime()->UnsetContextGlobals();
 
         PRBool alreadyCollecting = mCycleCollecting;
         mCycleCollecting = PR_TRUE;
         NoteJSRootTracer trc(&mJSRoots, cb);
         JS_TRACER_INIT(&trc, mCycleCollectionContext->GetJSContext(),
                        NoteJSRoot);
         JS_TraceRuntime(&trc);
         mCycleCollecting = alreadyCollecting;
@@ -648,17 +607,17 @@ nsresult
 nsXPConnect::FinishCycleCollection()
 {
 #ifdef DEBUG_CC
     if(mExplainCycleCollectionContext)
     {
         mCycleCollectionContext = nsnull;
         mExplainCycleCollectionContext = nsnull;
 
-        nsXPConnect::GetRuntime()->RestoreContextGlobals();
+        GetRuntime()->RestoreContextGlobals();
     }
 #endif
 
 #ifndef XPCONNECT_STANDALONE
     mScopes.Clear();
 #endif
 
 #ifdef DEBUG_CC
@@ -1012,21 +971,20 @@ public:
 #ifdef DEBUG_CC
         cb.DescribeNode(RefCounted, refCount, sizeof(JSContext),
                         "JSContext");
         cb.NoteNextEdgeName("[global object]");
 #else
         cb.DescribeNode(RefCounted, refCount);
 #endif
 
-        void* globalObject;
-        if(cx->globalObject)
-            globalObject = cx->globalObject;
-        else
-            globalObject = nsXPConnect::GetRuntime()->GetUnsetContextGlobal(cx);
+        void* globalObject = (cx->globalObject)
+                             ? cx->globalObject
+                             : nsXPConnect::GetRuntimeInstance()->
+                                 GetUnsetContextGlobal(cx);
 
         cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, globalObject);
 
         return NS_OK;
     }
 };
 
 static JSContextParticipant JSContext_cycleCollectorGlobal;
@@ -1439,17 +1397,17 @@ nsXPConnect::ReparentScopeAwareWrappers(
     if(!newScope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     // First, look through the old scope and find all of the wrappers that
     // we're going to move.
     nsVoidArray wrappersToMove;
 
     {   // scoped lock
-        XPCAutoLock lock(oldScope->GetRuntime()->GetMapLock());
+        XPCAutoLock lock(GetRuntime()->GetMapLock());
         Native2WrappedNativeMap *map = oldScope->GetWrappedNativeMap();
         wrappersToMove.SizeTo(map->Count());
         map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
     }
 
     // Now that we have the wrappers, reparent them to the new scope.
     for(PRInt32 i = 0, stop = wrappersToMove.Count(); i < stop; ++i)
     {
@@ -1695,36 +1653,30 @@ nsXPConnect::SetPendingException(nsIExce
     XPCPerThreadData* data = XPCPerThreadData::GetData(nsnull);
     if(!data)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     data->SetException(aPendingException);
     return NS_OK;
 }
 
-/* void syncJSContexts (); */
 NS_IMETHODIMP
 nsXPConnect::SyncJSContexts(void)
 {
-    XPCJSRuntime* rt = GetRuntime(this);
-    if(rt)
-        rt->SyncXPCContextList();
+    // Do-nothing compatibility function
     return NS_OK;
 }
 
 /* nsIXPCFunctionThisTranslator setFunctionThisTranslator (in nsIIDRef aIID, in nsIXPCFunctionThisTranslator aTranslator); */
 NS_IMETHODIMP
 nsXPConnect::SetFunctionThisTranslator(const nsIID & aIID,
                                        nsIXPCFunctionThisTranslator *aTranslator,
                                        nsIXPCFunctionThisTranslator **_retval)
 {
-    XPCJSRuntime* rt = GetRuntime(this);
-    if(!rt)
-        return NS_ERROR_UNEXPECTED;
-
+    XPCJSRuntime* rt = GetRuntime();
     nsIXPCFunctionThisTranslator* old;
     IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
 
     {
         XPCAutoLock lock(rt->GetMapLock()); // scoped lock
         if(_retval)
         {
             old = map->Find(aIID);
@@ -1736,20 +1688,17 @@ nsXPConnect::SetFunctionThisTranslator(c
     return NS_OK;
 }
 
 /* nsIXPCFunctionThisTranslator getFunctionThisTranslator (in nsIIDRef aIID); */
 NS_IMETHODIMP
 nsXPConnect::GetFunctionThisTranslator(const nsIID & aIID,
                                        nsIXPCFunctionThisTranslator **_retval)
 {
-    XPCJSRuntime* rt = GetRuntime(this);
-    if(!rt)
-        return NS_ERROR_UNEXPECTED;
-
+    XPCJSRuntime* rt = GetRuntime();
     nsIXPCFunctionThisTranslator* old;
     IID2ThisTranslatorMap* map = rt->GetThisTranslatorMap();
 
     {
         XPCAutoLock lock(rt->GetMapLock()); // scoped lock
         old = map->Find(aIID);
         NS_IF_ADDREF(old);
         *_retval = old;
@@ -1819,17 +1768,17 @@ nsXPConnect::RestoreWrappedNativePrototy
     }
 
     XPCNativeScriptableInfo *si = proto->GetScriptableInfo();
 
     if(si && si->GetFlags().DontSharePrototype())
         return UnexpectedFailure(NS_ERROR_INVALID_ARG);
 
     ClassInfo2WrappedNativeProtoMap* map = scope->GetWrappedNativeProtoMap();
-    XPCLock* lock = scope->GetRuntime()->GetMapLock();
+    XPCLock* lock = GetRuntime()->GetMapLock();
 
     {   // scoped lock
         XPCAutoLock al(lock);
 
         XPCWrappedNativeProtoMap* detachedMap =
             GetRuntime()->GetDetachedWrappedNativeProtoMap();
 
         // If we're replacing an old proto, make sure to put it on the
@@ -2007,18 +1956,17 @@ nsXPConnect::UpdateXOWs(JSContext* aJSCo
 {
     typedef WrappedNative2WrapperMap::Link Link;
     XPCWrappedNative* wn = static_cast<XPCWrappedNative *>(aObject);
     XPCWrappedNativeScope* scope = wn->GetScope();
     WrappedNative2WrapperMap* map = scope->GetWrapperMap();
     Link* list;
 
     {
-        XPCJSRuntime* rt = nsXPConnect::GetRuntime();
-        XPCAutoLock al(rt->GetMapLock());
+        XPCAutoLock al(GetRuntime()->GetMapLock());
 
         list = map->FindLink(wn->GetFlatJSObject());
     }
 
     if(!list)
         return NS_OK; // No wrappers to update.
 
     AutoJSRequestWithNoCallContext req(aJSContext);
@@ -2074,17 +2022,16 @@ nsXPConnect::ReleaseJSContext(JSContext 
                         DEBUG_StackHasJSContext(aJSContext),
                      "JSContext still in threadjscontextstack!");
     }
     
     if(noGC)
         JS_DestroyContextNoGC(aJSContext);
     else
         JS_DestroyContext(aJSContext);
-    SyncJSContexts();
     return NS_OK;
 }
 
 /* void debugDump (in short depth); */
 NS_IMETHODIMP
 nsXPConnect::DebugDump(PRInt16 depth)
 {
 #ifdef DEBUG
@@ -2253,25 +2200,17 @@ nsXPConnect::JSToVariant(JSContext* ctx,
 /* void flagSystemFilenamePrefix (in string filenamePrefix,
  *                                in PRBool aWantNativeWrappers); */
 NS_IMETHODIMP 
 nsXPConnect::FlagSystemFilenamePrefix(const char *aFilenamePrefix,
                                       PRBool aWantNativeWrappers)
 {
     NS_PRECONDITION(aFilenamePrefix, "bad param");
 
-    nsIJSRuntimeService* rtsvc = nsXPConnect::GetJSRuntimeService();
-    if(!rtsvc)
-        return NS_ERROR_NOT_INITIALIZED;
-
-    JSRuntime* rt;
-    nsresult rv = rtsvc->GetRuntime(&rt);
-    if(NS_FAILED(rv))
-        return rv;
-
+    JSRuntime* rt = GetRuntime()->GetJSRuntime();;
     uint32 flags = JSFILENAME_SYSTEM;
     if(aWantNativeWrappers)
         flags |= JSFILENAME_PROTECTED;
     if(!JS_FlagScriptFilenamePrefix(rt, aFilenamePrefix, flags))
         return NS_ERROR_OUT_OF_MEMORY;
     return NS_OK;
 }
 
@@ -2329,16 +2268,52 @@ nsXPConnect::DefineDOMQuickStubs(JSConte
                                  PRUint32 flags,
                                  PRUint32 interfaceCount,
                                  const nsIID * *interfaceArray)
 {
     return DOM_DefineQuickStubs(cx, proto, flags,
                                 interfaceCount, interfaceArray);
 }
 
+/* attribute JSRuntime runtime; */
+NS_IMETHODIMP
+nsXPConnect::GetRuntime(JSRuntime **runtime)
+{
+    if(!runtime)
+        return NS_ERROR_NULL_POINTER;
+
+    *runtime = GetRuntime()->GetJSRuntime();
+    return NS_OK;
+}
+
+/* attribute nsIXPCScriptable backstagePass; */
+NS_IMETHODIMP
+nsXPConnect::GetBackstagePass(nsIXPCScriptable **bsp)
+{
+    if(!mBackstagePass) {
+#ifndef XPCONNECT_STANDALONE
+        nsCOMPtr<nsIPrincipal> sysprin;
+        nsCOMPtr<nsIScriptSecurityManager> secman =
+            do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
+        if(!secman)
+            return NS_ERROR_NOT_AVAILABLE;
+        if(NS_FAILED(secman->GetSystemPrincipal(getter_AddRefs(sysprin))))
+            return NS_ERROR_NOT_AVAILABLE;
+
+        mBackstagePass = new BackstagePass(sysprin);
+#else
+        mBackstagePass = new BackstagePass();
+#endif
+        if(!mBackstagePass)
+            return NS_ERROR_OUT_OF_MEMORY;
+    }
+    NS_ADDREF(*bsp = mBackstagePass);
+    return NS_OK;
+}
+
 /* 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/xpccallcontext.cpp
+++ b/js/src/xpconnect/src/xpccallcontext.cpp
@@ -119,30 +119,17 @@ XPCCallContext::XPCCallContext(XPCContex
         if(NS_FAILED(stack->Push(mJSContext)))
         {
             NS_ERROR("bad!");
             return;
         }
         mContextPopRequired = JS_TRUE;
     }
 
-    // Try to get the JSContext -> XPCContext mapping from the cache.
-    // FWIW... quicky tests show this hitting ~ 95% of the time.
-    // That is a *lot* of locking we can skip in nsXPConnect::GetContext.
-    mXPCContext = mThreadData->GetRecentXPCContext(mJSContext);
-
-    if(!mXPCContext)
-    {
-        if(!(mXPCContext = nsXPConnect::GetContext(mJSContext, mXPC)))
-            return;
-
-        // Fill the cache.
-        mThreadData->SetRecentContext(mJSContext, mXPCContext);
-    }
-
+    mXPCContext = XPCContext::GetXPCContext(mJSContext);
     mPrevCallerLanguage = mXPCContext->SetCallingLangType(mCallerLanguage);
 
     // hook into call context chain for our thread
     mPrevCallContext = mThreadData->SetCallContext(this);
 
     mState = HAVE_CONTEXT;
 
     if(!obj)
@@ -347,17 +334,16 @@ XPCCallContext::~XPCCallContext()
                    mJSContext);
 #endif
             NS_ASSERTION(!mThreadData->GetJSContextStack() || 
                          !mThreadData->GetJSContextStack()->
                             DEBUG_StackHasJSContext(mJSContext),
                          "JSContext still in threadjscontextstack!");
         
             JS_DestroyContext(mJSContext);
-            mXPC->SyncJSContexts();
         }
         else
         {
             // Don't clear newborns if JS frames (compilation or execution)
             // are active!  Doing so violates ancient invariants in the JS
             // engine, and it's not necessary to fix JS component leaks.
             if(!mJSContext->fp)
                 JS_ClearNewbornRoots(mJSContext);
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3892,17 +3892,17 @@ nsXPCComponents::GetManager(nsIComponent
 
 /* PRBool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in JSVal id, in PRUint32 flags, out JSObjectPtr objp); */
 NS_IMETHODIMP
 nsXPCComponents::NewResolve(nsIXPConnectWrappedNative *wrapper,
                             JSContext * cx, JSObject * obj,
                             jsval id, PRUint32 flags,
                             JSObject * *objp, PRBool *_retval)
 {
-    XPCJSRuntime* rt = nsXPConnect::GetRuntime();
+    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if(!rt)
         return NS_ERROR_FAILURE;
 
     jsid idid;
     uintN attrs = 0;
 
     if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_LAST_RESULT))
     {
@@ -3923,17 +3923,17 @@ nsXPCComponents::NewResolve(nsIXPConnect
 }
 
 /* PRBool getProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in JSVal id, in JSValPtr vp); */
 NS_IMETHODIMP
 nsXPCComponents::GetProperty(nsIXPConnectWrappedNative *wrapper,
                              JSContext * cx, JSObject * obj,
                              jsval id, jsval * vp, PRBool *_retval)
 {
-    XPCContext* xpcc = nsXPConnect::GetContext(cx);
+    XPCContext* xpcc = XPCContext::GetXPCContext(cx);
     if(!xpcc)
         return NS_ERROR_FAILURE;
 
     PRBool doResult = JS_FALSE;
     nsresult res;
     XPCJSRuntime* rt = xpcc->GetRuntime();
     if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_LAST_RESULT))
     {
@@ -3958,17 +3958,17 @@ nsXPCComponents::GetProperty(nsIXPConnec
 }
 
 /* PRBool setProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in JSVal id, in JSValPtr vp); */
 NS_IMETHODIMP
 nsXPCComponents::SetProperty(nsIXPConnectWrappedNative *wrapper,
                              JSContext * cx, JSObject * obj, jsval id,
                              jsval * vp, PRBool *_retval)
 {
-    XPCContext* xpcc = nsXPConnect::GetContext(cx);
+    XPCContext* xpcc = XPCContext::GetXPCContext(cx);
     if(!xpcc)
         return NS_ERROR_FAILURE;
 
     XPCJSRuntime* rt = xpcc->GetRuntime();
     if(!rt)
         return NS_ERROR_FAILURE;
 
     if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_RETURN_CODE))
--- a/js/src/xpconnect/src/xpccontext.cpp
+++ b/js/src/xpconnect/src/xpccontext.cpp
@@ -39,51 +39,42 @@
  * ***** END LICENSE BLOCK ***** */
 
 /* Per JSContext object. */
 
 #include "xpcprivate.h"
 
 /***************************************************************************/
 
-// static
-XPCContext*
-XPCContext::newXPCContext(XPCJSRuntime* aRuntime,
-                          JSContext* aJSContext)
-{
-    NS_PRECONDITION(aRuntime,"bad param");
-    NS_PRECONDITION(aJSContext,"bad param");
-    NS_ASSERTION(JS_GetRuntime(aJSContext) == aRuntime->GetJSRuntime(),
-                 "XPConnect can not be used on multiple JSRuntimes!");
-
-    return new XPCContext(aRuntime, aJSContext);
-}
-
 XPCContext::XPCContext(XPCJSRuntime* aRuntime,
                        JSContext* aJSContext)
     :   mRuntime(aRuntime),
         mJSContext(aJSContext),
         mLastResult(NS_OK),
         mPendingResult(NS_OK),
         mSecurityManager(nsnull),
         mException(nsnull),
         mCallingLangType(LANG_UNKNOWN),
-        mSecurityManagerFlags(0),
-        mMarked((JSPackedBool) JS_FALSE)
+        mSecurityManagerFlags(0)
 {
     MOZ_COUNT_CTOR(XPCContext);
 
     PR_INIT_CLIST(&mScopes);
     for(const char** p =  XPC_ARG_FORMATTER_FORMAT_STRINGS; *p; p++)
         JS_AddArgumentFormatter(mJSContext, *p, XPC_JSArgumentFormatter);
+
+    NS_ASSERTION(!mJSContext->data2, "Must be null");
+    mJSContext->data2 = this;
 }
 
 XPCContext::~XPCContext()
 {
     MOZ_COUNT_DTOR(XPCContext);
+    NS_ASSERTION(mJSContext->data2 == this, "Must match this");
+    mJSContext->data2 = nsnull;
     NS_IF_RELEASE(mException);
     NS_IF_RELEASE(mSecurityManager);
 
     // Iterate over our scopes and tell them that we have been destroyed
     for(PRCList *scopeptr = PR_NEXT_LINK(&mScopes);
         scopeptr != &mScopes;
         scopeptr = PR_NEXT_LINK(scopeptr))
     {
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -1464,30 +1464,26 @@ XPCConvert::JSValToXPCException(XPCCallC
 
             // heuristic to see if it might be usable as an xpcexception
             if(JS_GetPropertyAttributes(cx, obj, "message", &ignored, &found) &&
                found &&
                JS_GetPropertyAttributes(cx, obj, "result", &ignored, &found) &&
                found)
             {
                 // lets try to build a wrapper around the JSObject
-                XPCContext* xpcc;
-                if(nsnull != (xpcc = nsXPConnect::GetContext(cx)))
-                {
-                    nsXPCWrappedJS* jswrapper;
-                    nsresult rv =
-                        nsXPCWrappedJS::GetNewOrUsed(ccx, obj,
-                                                NS_GET_IID(nsIException),
-                                                nsnull, &jswrapper);
-                    if(NS_FAILED(rv))
-                        return rv;
-                    *exceptn = reinterpret_cast<nsIException*>
-                                               (jswrapper);
-                    return NS_OK;
-                }
+                nsXPCWrappedJS* jswrapper;
+                nsresult rv =
+                    nsXPCWrappedJS::GetNewOrUsed(ccx, obj,
+                                                 NS_GET_IID(nsIException),
+                                                 nsnull, &jswrapper);
+                if(NS_FAILED(rv))
+                    return rv;
+                *exceptn = reinterpret_cast<nsIException*>
+                           (jswrapper);
+                return NS_OK;
             }
 
 
             // XXX we should do a check against 'js_ErrorClass' here and
             // do the right thing - even though it has no JSErrorReport,
             // The fact that it is a JSError exceptions means we can extract
             // particular info and our 'result' should reflect that.
 
--- a/js/src/xpconnect/src/xpcexception.cpp
+++ b/js/src/xpconnect/src/xpcexception.cpp
@@ -162,17 +162,17 @@ nsXPCException::GetThrownJSVal(jsval *vp
     }
     return PR_FALSE;
 }
 
 void
 nsXPCException::SetThrownJSVal(jsval v)
 {
     mThrownJSVal = JSVAL_IS_TRACEABLE(v)
-        ? new XPCTraceableVariant(nsXPConnect::GetRuntime(), v)
+        ? new XPCTraceableVariant(nsXPConnect::GetRuntimeInstance(), v)
         : new XPCVariant(v);
 }
 
 void
 nsXPCException::Reset()
 {
     if(mMessage)
     {
--- a/js/src/xpconnect/src/xpcforwards.h
+++ b/js/src/xpconnect/src/xpcforwards.h
@@ -69,17 +69,16 @@ class XPCNativeScriptableInfo;
 class XPCNativeScriptableCreateInfo;
 
 class XPCTraceableVariant;
 class XPCJSObjectHolder;
 
 class JSObject2WrappedJSMap;
 class Native2WrappedNativeMap;
 class IID2WrappedJSClassMap;
-class JSContext2XPCContextMap;
 class IID2NativeInterfaceMap;
 class ClassInfo2NativeSetMap;
 class ClassInfo2WrappedNativeProtoMap;
 class NativeSetMap;
 class IID2ThisTranslatorMap;
 class XPCNativeScriptableSharedMap;
 class XPCWrappedNativeProtoMap;
 class XPCNativeWrapperMap;
--- a/js/src/xpconnect/src/xpcinlines.h
+++ b/js/src/xpconnect/src/xpcinlines.h
@@ -726,21 +726,17 @@ xpc_NewSystemInheritingJSObject(JSContex
 {
     return JS_NewSystemObject(cx, clasp, proto, parent,
                               JS_IsSystemObject(cx, parent));
 }
 
 inline jsval
 GetRTStringByIndex(JSContext *cx, uintN index)
 {
-  XPCJSRuntime *rt = nsXPConnect::GetRuntime();
-
-  if (!rt)
-    return JSVAL_VOID;
-
+  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
   return ID_TO_VALUE(rt->GetStringID(index));
 }
 
 inline
 JSBool ThrowBadParam(nsresult rv, uintN paramNum, XPCCallContext& ccx)
 {
     XPCThrower::ThrowBadParam(rv, paramNum, ccx);
     return JS_FALSE;
--- a/js/src/xpconnect/src/xpcjsid.cpp
+++ b/js/src/xpconnect/src/xpcjsid.cpp
@@ -790,17 +790,17 @@ nsJSCID::CreateInstance(nsISupports **_r
     ccxp->GetRetValPtr(&vp);
 
     nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     ccxp->GetCalleeWrapper(getter_AddRefs(wrapper));
     wrapper->GetJSObject(&obj);
 
     // Do the security check if necessary
 
-    XPCContext* xpcc = nsXPConnect::GetContext(cx);
+    XPCContext* xpcc = XPCContext::GetXPCContext(cx);
 
     nsIXPCSecurityManager* sm;
     sm = xpcc->GetAppropriateSecurityManager(
                         nsIXPCSecurityManager::HOOK_CREATE_INSTANCE);
     if(sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID())))
     {
         NS_ASSERTION(JS_IsExceptionPending(cx),
                      "security manager vetoed CreateInstance without setting exception");
@@ -863,17 +863,17 @@ nsJSCID::GetService(nsISupports **_retva
     ccxp->GetRetValPtr(&vp);
 
     nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     ccxp->GetCalleeWrapper(getter_AddRefs(wrapper));
     wrapper->GetJSObject(&obj);
 
     // Do the security check if necessary
 
-    XPCContext* xpcc = nsXPConnect::GetContext(cx);
+    XPCContext* xpcc = XPCContext::GetXPCContext(cx);
 
     nsIXPCSecurityManager* sm;
     sm = xpcc->GetAppropriateSecurityManager(
                         nsIXPCSecurityManager::HOOK_GET_SERVICE);
     if(sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID())))
     {
         NS_ASSERTION(JS_IsExceptionPending(cx),
                      "security manager vetoed GetService without setting exception");
@@ -909,17 +909,17 @@ nsJSCID::GetService(nsISupports **_retva
 
 /* PRBool construct (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in PRUint32 argc, in JSValPtr argv, in JSValPtr vp); */
 NS_IMETHODIMP
 nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper,
                    JSContext * cx, JSObject * obj,
                    PRUint32 argc, jsval * argv, jsval * vp,
                    PRBool *_retval)
 {
-    XPCJSRuntime* rt = nsXPConnect::GetRuntime();
+    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if(!rt)
         return NS_ERROR_FAILURE;
 
     // 'push' a call context and call on it
     XPCCallContext ccx(JS_CALLER, cx, obj, nsnull,
                        rt->GetStringJSVal(XPCJSRuntime::IDX_CREATE_INSTANCE),
                        argc, argv, vp);
 
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -65,22 +65,16 @@ const char* XPCJSRuntime::mStrings[] = {
     , "GeckoActiveXObject"  // IDX_ACTIVEX_OBJECT
     , "COMObject"           // IDX_COMOBJECT
     , "supports"            // IDX_ACTIVEX_SUPPORTS
 #endif
 };
 
 /***************************************************************************/
 
-// ContextCallback calls are chained
-static JSContextCallback gOldJSContextCallback;
-
-// GCCallback calls are chained
-static JSGCCallback gOldJSGCCallback;
-
 // data holder class for the enumerator callback below
 struct JSDyingJSObjectData
 {
     JSContext* cx;
     nsVoidArray* array;
 };
 
 static JSDHashOperator
@@ -228,34 +222,30 @@ DetachedWrappedNativeProtoMarker(JSDHash
     proto->Mark();
     return JS_DHASH_NEXT;
 }
 
 // GCCallback calls are chained
 static JSBool
 ContextCallback(JSContext *cx, uintN operation)
 {
-    XPCJSRuntime* self = nsXPConnect::GetRuntime();
-    if (self)
+    XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
+    if(self)
     {
-        if (operation == JSCONTEXT_NEW)
+        if(operation == JSCONTEXT_NEW)
         {
-            // Set the limits on the native and script stack space.
-            XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
-            if(tls)
-            {
-                JS_SetThreadStackLimit(cx, tls->GetStackLimit());
-            }
-            JS_SetScriptStackQuota(cx, 100*1024*1024);
+            if(!self->OnJSContextNew(cx))
+                return JS_FALSE;
+        }
+        else if(operation == JSCONTEXT_DESTROY)
+        {
+            delete XPCContext::GetXPCContext(cx);
         }
     }
-
-    return gOldJSContextCallback
-           ? gOldJSContextCallback(cx, operation)
-           : JS_TRUE;
+    return JS_TRUE;
 }
 
 struct ObjectHolder : public JSDHashEntryHdr
 {
     void *holder;
     nsScriptObjectTracer* tracer;
 };
 
@@ -516,17 +506,17 @@ JSObject* XPCJSRuntime::GetUnsetContextG
            nsnull;
 }
 
 // static
 JSBool XPCJSRuntime::GCCallback(JSContext *cx, JSGCStatus status)
 {
     nsVoidArray* dyingWrappedJSArray;
 
-    XPCJSRuntime* self = nsXPConnect::GetRuntime();
+    XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     if(self)
     {
         switch(status)
         {
             case JSGC_BEGIN:
             {
                 if(!NS_IsMainThread())
                 {
@@ -822,18 +812,17 @@ JSBool XPCJSRuntime::GCCallback(JSContex
 #endif
                 break;
             }
             default:
                 break;
         }
     }
 
-    // always chain to old GCCallback if non-null.
-    return gOldJSGCCallback ? gOldJSGCCallback(cx, status) : JS_TRUE;
+    return JS_TRUE;
 }
 
 /***************************************************************************/
 
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
 static JSDHashOperator
 DEBUG_WrapperChecker(JSDHashTable *table, JSDHashEntryHdr *hdr,
                      uint32 number, void *arg)
@@ -885,23 +874,16 @@ XPCJSRuntime::~XPCJSRuntime()
     while(JS_ContextIterator(mJSRuntime, &iter))
         count ++;
     if(count)
         printf("deleting XPCJSRuntime with %d live JSContexts\n", count);
     }
 #endif
 
     // clean up and destroy maps...
-
-    if(mContextMap)
-    {
-        PurgeXPCContextList();
-        delete mContextMap;
-    }
-
     if(mWrappedJSMap)
     {
 #ifdef XPC_DUMP_AT_SHUTDOWN
         uint32 count = mWrappedJSMap->Count();
         if(count)
             printf("deleting XPCJSRuntime with %d live wrapped JSObject\n", (int)count);
 #endif
         mWrappedJSMap->Enumerate(WrappedJSShutdownMarker, mJSRuntime);
@@ -945,17 +927,16 @@ XPCJSRuntime::~XPCJSRuntime()
         if(count)
             printf("deleting XPCJSRuntime with %d live XPCNativeSets\n", (int)count);
 #endif
         delete mNativeSetMap;
     }
 
     if(mMapLock)
         XPCAutoLock::DestroyLock(mMapLock);
-    NS_IF_RELEASE(mJSRuntimeService);
 
     if(mThisTranslatorMap)
     {
 #ifdef XPC_DUMP_AT_SHUTDOWN
         uint32 count = mThisTranslatorMap->Count();
         if(count)
             printf("deleting XPCJSRuntime with %d live ThisTranslator\n", (int)count);
 #endif
@@ -1014,37 +995,42 @@ XPCJSRuntime::~XPCJSRuntime()
         delete mExplicitNativeWrapperMap;
     }
 
     // unwire the readable/JSString sharing magic
     XPCStringConvert::ShutdownDOMStringFinalizer();
 
     XPCConvert::RemoveXPCOMUCStringFinalizer();
 
-    gOldJSGCCallback = NULL;
-    gOldJSContextCallback = NULL;
-
     if(mJSHolders.ops)
     {
         JS_DHashTableFinish(&mJSHolders);
         mJSHolders.ops = nsnull;
     }
     if(mClearedGlobalObjects.ops)
     {
         JS_DHashTableFinish(&mClearedGlobalObjects);
         mClearedGlobalObjects.ops = nsnull;
     }
+
+    if(mJSRuntime)
+    {
+        JS_DestroyRuntime(mJSRuntime);
+        JS_ShutDown();
+#ifdef DEBUG_shaver_off
+        fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
+#endif
+    }
+
+    XPCPerThreadData::ShutDown();
 }
 
-XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect,
-                           nsIJSRuntimeService* aJSRuntimeService)
+XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
  : mXPConnect(aXPConnect),
    mJSRuntime(nsnull),
-   mJSRuntimeService(aJSRuntimeService),
-   mContextMap(JSContext2XPCContextMap::newMap(XPC_CONTEXT_MAP_SIZE)),
    mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_SIZE)),
    mWrappedJSClassMap(IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_SIZE)),
    mIID2NativeInterfaceMap(IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_SIZE)),
    mClassInfo2NativeSetMap(ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
    mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_SIZE)),
    mThisTranslatorMap(IID2ThisTranslatorMap::newMap(XPC_THIS_TRANSLATOR_MAP_SIZE)),
    mNativeScriptableSharedMap(XPCNativeScriptableSharedMap::newMap(XPC_NATIVE_JSCLASS_MAP_SIZE)),
    mDyingWrappedNativeProtoMap(XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_SIZE)),
@@ -1063,28 +1049,45 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     DEBUG_WrappedNativeHashtable =
         JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
                          sizeof(JSDHashEntryStub), 128);
 #endif
 
     // these jsids filled in later when we have a JSContext to work with.
     mStrIDs[0] = 0;
 
-    if(mJSRuntimeService)
-    {
-        NS_ADDREF(mJSRuntimeService);
-        mJSRuntimeService->GetRuntime(&mJSRuntime);
-    }
+    // Call XPCPerThreadData::GetData to initialize
+    // XPCPerThreadData::gTLSIndex before initializing
+    // JSRuntime::threadTPIndex in JS_NewRuntime.
+    //
+    // XPConnect uses a thread local storage (XPCPerThreadData) indexed by
+    // XPCPerThreadData::gTLSIndex, and SpiderMonkey GC uses a thread local
+    // storage indexed by JSRuntime::threadTPIndex.
+    //
+    // The destructor for XPCPerThreadData::gTLSIndex may access
+    // thread local storage indexed by JSRuntime::threadTPIndex.
+    // Thus, the destructor for JSRuntime::threadTPIndex must be called
+    // later than the one for XPCPerThreadData::gTLSIndex.
+    //
+    // We rely on the implementation of NSPR that calls destructors at
+    // the same order of calling PR_NewThreadPrivateIndex.
+    XPCPerThreadData::GetData(nsnull);
 
-    NS_ASSERTION(!gOldJSGCCallback, "XPCJSRuntime created more than once");
+    mJSRuntime = JS_NewRuntime(32L * 1024L * 1024L); // pref ?
     if(mJSRuntime)
     {
-        gOldJSContextCallback = JS_SetContextCallback(mJSRuntime,
-                                                      ContextCallback);
-        gOldJSGCCallback = JS_SetGCCallbackRT(mJSRuntime, GCCallback);
+        // Unconstrain the runtime's threshold on nominal heap size, to avoid
+        // triggering GC too often if operating continuously near an arbitrary
+        // finite threshold (0xffffffff is infinity for uint32 parameters).
+        // This leaves the maximum-JS_malloc-bytes threshold still in effect
+        // to cause period, and we hope hygienic, last-ditch GCs from within
+        // the GC's allocator.
+        JS_SetGCParameter(mJSRuntime, JSGC_MAX_BYTES, 0xffffffff);
+        JS_SetContextCallback(mJSRuntime, ContextCallback);
+        JS_SetGCCallbackRT(mJSRuntime, GCCallback);
         JS_SetExtraGCRoots(mJSRuntime, TraceJS, this);
     }
 
     if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
                           sizeof(ObjectHolder), 512))
         mJSHolders.ops = nsnull;
     if(!JS_DHashTableInit(&mClearedGlobalObjects, JS_DHashGetStubOps(), nsnull,
                           sizeof(ClearedGlobalObject), JS_DHASH_MIN_SIZE))
@@ -1094,30 +1097,24 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
 #ifdef DEBUG
     if(mJSRuntime && !JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
         xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
 #endif
 }
 
 // static
 XPCJSRuntime*
-XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect,
-                              nsIJSRuntimeService* aJSRuntimeService)
+XPCJSRuntime::newXPCJSRuntime(nsXPConnect* aXPConnect)
 {
     NS_PRECONDITION(aXPConnect,"bad param");
-    NS_PRECONDITION(aJSRuntimeService,"bad param");
 
-    XPCJSRuntime* self;
-
-    self = new XPCJSRuntime(aXPConnect,
-                            aJSRuntimeService);
+    XPCJSRuntime* self = new XPCJSRuntime(aXPConnect);
 
     if(self                                  &&
        self->GetJSRuntime()                  &&
-       self->GetContextMap()                 &&
        self->GetWrappedJSMap()               &&
        self->GetWrappedJSClassMap()          &&
        self->GetIID2NativeInterfaceMap()     &&
        self->GetClassInfo2NativeSetMap()     &&
        self->GetNativeSetMap()               &&
        self->GetThisTranslatorMap()          &&
        self->GetNativeScriptableSharedMap()  &&
        self->GetDyingWrappedNativeProtoMap() &&
@@ -1125,135 +1122,49 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnec
        self->GetMapLock())
     {
         return self;
     }
     delete self;
     return nsnull;
 }
 
-XPCContext*
-XPCJSRuntime::GetXPCContext(JSContext* cx)
+JSBool
+XPCJSRuntime::OnJSContextNew(JSContext *cx)
 {
-    XPCContext* xpcc;
-
-    // find it in the map.
-
-    { // scoped lock
-        XPCAutoLock lock(GetMapLock());
-        xpcc = mContextMap->Find(cx);
-    }
-
-    // else resync with the JSRuntime's JSContext list and see if it is found
-    if(!xpcc)
-        xpcc = SyncXPCContextList(cx);
-    return xpcc;
-}
-
-
-static JSDHashOperator
-SweepContextsCB(JSDHashTable *table, JSDHashEntryHdr *hdr,
-                uint32 number, void *arg)
-{
-    XPCContext* xpcc = ((JSContext2XPCContextMap::Entry*)hdr)->value;
-    if(xpcc->IsMarked())
+    // if it is our first context then we need to generate our string ids
+    JSBool ok = JS_TRUE;
+    if(!mStrIDs[0])
     {
-        xpcc->Unmark();
-        return JS_DHASH_NEXT;
+        JSAutoRequest ar(cx);
+        for(uintN i = 0; i < IDX_TOTAL_COUNT; i++)
+        {
+            JSString* str = JS_InternString(cx, mStrings[i]);
+            if(!str || !JS_ValueToId(cx, STRING_TO_JSVAL(str), &mStrIDs[i]))
+            {
+                mStrIDs[0] = 0;
+                ok = JS_FALSE;
+                break;
+            }
+            mStrJSVals[i] = STRING_TO_JSVAL(str);
+        }
     }
-
-    // this XPCContext represents a dead JSContext - delete it
-    delete xpcc;
-    return JS_DHASH_REMOVE;
-}
-
-XPCContext*
-XPCJSRuntime::SyncXPCContextList(JSContext* cx /* = nsnull */)
-{
-    // hold the map lock through this whole thing
-    XPCAutoLock lock(GetMapLock());
-
-    XPCContext* found = nsnull;
-
-    // add XPCContexts that represent any JSContexts we have not seen before
-    JSContext *cur, *iter = nsnull;
-    while(nsnull != (cur = JS_ContextIterator(mJSRuntime, &iter)))
-    {
-        XPCContext* xpcc = mContextMap->Find(cur);
-
-        if(!xpcc)
-        {
-            xpcc = XPCContext::newXPCContext(this, cur);
-            if(xpcc)
-                mContextMap->Add(xpcc);
-        }
-        if(xpcc)
-        {
-            xpcc->Mark();
-        }
-
-        // if it is our first context then we need to generate our string ids
-        if(!mStrIDs[0])
-        {
-            JSAutoRequest ar(cur);
-            GenerateStringIDs(cur);
-        }
-
-        if(cx && cx == cur)
-            found = xpcc;
-    }
-    // get rid of any XPCContexts that represent dead JSContexts
-    mContextMap->Enumerate(SweepContextsCB, 0);
+    if (!ok)
+        return JS_FALSE;
 
     XPCPerThreadData* tls = XPCPerThreadData::GetData(cx);
-    if(tls)
-    {
-        if(found)
-            tls->SetRecentContext(cx, found);
-        else
-            tls->ClearRecentContext();
-    }
-
-    return found;
-}
-
-
-static JSDHashOperator
-PurgeContextsCB(JSDHashTable *table, JSDHashEntryHdr *hdr,
-                uint32 number, void *arg)
-{
-    delete ((JSContext2XPCContextMap::Entry*)hdr)->value;
-    return JS_DHASH_REMOVE;
-}
+    if(!tls)
+        return JS_FALSE;
 
-void
-XPCJSRuntime::PurgeXPCContextList()
-{
-    // hold the map lock through this whole thing
-    XPCAutoLock lock(GetMapLock());
-
-    // get rid of all XPCContexts
-    mContextMap->Enumerate(PurgeContextsCB, nsnull);
-}
+    XPCContext* xpc = new XPCContext(this, cx);
+    if (!xpc)
+        return JS_FALSE;
 
-JSBool
-XPCJSRuntime::GenerateStringIDs(JSContext* cx)
-{
-    NS_PRECONDITION(!mStrIDs[0],"string ids generated twice!");
-    for(uintN i = 0; i < IDX_TOTAL_COUNT; i++)
-    {
-        JSString* str = JS_InternString(cx, mStrings[i]);
-        if(!str || !JS_ValueToId(cx, STRING_TO_JSVAL(str), &mStrIDs[i]))
-        {
-            mStrIDs[0] = 0;
-            return JS_FALSE;
-        }
-
-        mStrJSVals[i] = STRING_TO_JSVAL(str);
-    }
+    JS_SetThreadStackLimit(cx, tls->GetStackLimit());
+    JS_SetScriptStackQuota(cx, 100*1024*1024);
     return JS_TRUE;
 }
 
 JSBool
 XPCJSRuntime::DeferredRelease(nsISupports* obj)
 {
     NS_ASSERTION(obj, "bad param");
 
@@ -1266,23 +1177,16 @@ XPCJSRuntime::DeferredRelease(nsISupport
     }
     return mNativesToReleaseArray.AppendElement(obj);
 }
 
 /***************************************************************************/
 
 #ifdef DEBUG
 static JSDHashOperator
-ContextMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
-                         uint32 number, void *arg)
-{
-    ((JSContext2XPCContextMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
-    return JS_DHASH_NEXT;
-}
-static JSDHashOperator
 WrappedJSClassMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
                                 uint32 number, void *arg)
 {
     ((IID2WrappedJSClassMap::Entry*)hdr)->value->DebugDump(*(PRInt16*)arg);
     return JS_DHASH_NEXT;
 }
 static JSDHashOperator
 WrappedJSMapDumpEnumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
@@ -1305,29 +1209,33 @@ XPCJSRuntime::DebugDump(PRInt16 depth)
 {
 #ifdef DEBUG
     depth--;
     XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
         XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("mXPConnect @ %x", mXPConnect));
         XPC_LOG_ALWAYS(("mJSRuntime @ %x", mJSRuntime));
         XPC_LOG_ALWAYS(("mMapLock @ %x", mMapLock));
-        XPC_LOG_ALWAYS(("mJSRuntimeService @ %x", mJSRuntimeService));
 
         XPC_LOG_ALWAYS(("mWrappedJSToReleaseArray @ %x with %d wrappers(s)", \
                          &mWrappedJSToReleaseArray,
                          mWrappedJSToReleaseArray.Count()));
 
-        XPC_LOG_ALWAYS(("mContextMap @ %x with %d context(s)", \
-                         mContextMap, mContextMap ? mContextMap->Count() : 0));
-        // iterate contexts...
-        if(depth && mContextMap && mContextMap->Count())
+        int cxCount = 0;
+        JSContext* iter = nsnull;
+        while(JS_ContextIterator(mJSRuntime, &iter))
+            ++cxCount;
+        XPC_LOG_ALWAYS(("%d JS context(s)", cxCount));
+
+        iter = nsnull;
+        while(JS_ContextIterator(mJSRuntime, &iter))
         {
+            XPCContext *xpc = XPCContext::GetXPCContext(iter);
             XPC_LOG_INDENT();
-            mContextMap->Enumerate(ContextMapDumpEnumerator, &depth);
+            xpc->DebugDump(depth);
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)", \
                          mWrappedJSClassMap, mWrappedJSClassMap ? \
                                             mWrappedJSClassMap->Count() : 0));
         // iterate wrappersclasses...
         if(depth && mWrappedJSClassMap && mWrappedJSClassMap->Count())
--- a/js/src/xpconnect/src/xpcmaps.cpp
+++ b/js/src/xpconnect/src/xpcmaps.cpp
@@ -116,43 +116,16 @@ HashNativeKey(JSDHashTable *table, const
                 h ^= (JSHashNumber) NS_PTR_TO_INT32(*(Current++)) >> 2;
         }
     }
 
     return h;
 }
 
 /***************************************************************************/
-// implement JSContext2XPCContextMap...
-
-// static
-JSContext2XPCContextMap*
-JSContext2XPCContextMap::newMap(int size)
-{
-    JSContext2XPCContextMap* map = new JSContext2XPCContextMap(size);
-    if(map && map->mTable)
-        return map;
-    delete map;
-    return nsnull;
-}
-
-
-JSContext2XPCContextMap::JSContext2XPCContextMap(int size)
-{
-    mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull,
-                              sizeof(Entry), size);
-}
-
-JSContext2XPCContextMap::~JSContext2XPCContextMap()
-{
-    if(mTable)
-        JS_DHashTableDestroy(mTable);
-}
-
-/***************************************************************************/
 // implement JSObject2WrappedJSMap...
 
 // static
 JSObject2WrappedJSMap*
 JSObject2WrappedJSMap::newMap(int size)
 {
     JSObject2WrappedJSMap* map = new JSObject2WrappedJSMap(size);
     if(map && map->mTable)
--- a/js/src/xpconnect/src/xpcmaps.h
+++ b/js/src/xpconnect/src/xpcmaps.h
@@ -48,70 +48,16 @@
 // Note that most of the declarations for hash table entries begin with
 // a pointer to something or another. This makes them look enough like
 // the JSDHashEntryStub struct that the default OPs (JS_DHashGetStubOps())
 // just do the right thing for most of our needs.
 
 // no virtuals in the maps - all the common stuff inlined
 // templates could be used to good effect here.
 
-class JSContext2XPCContextMap
-{
-public:
-    struct Entry : public JSDHashEntryHdr
-    {
-        JSContext*  key;
-        XPCContext* value;
-    };
-
-    static JSContext2XPCContextMap* newMap(int size);
-
-    inline XPCContext* Find(JSContext* cx)
-    {
-        NS_PRECONDITION(cx,"bad param");
-        Entry* entry = (Entry*)
-            JS_DHashTableOperate(mTable, cx, JS_DHASH_LOOKUP);
-        if(JS_DHASH_ENTRY_IS_FREE(entry))
-            return nsnull;
-        return entry->value;
-    }
-
-    inline XPCContext* Add(XPCContext* xpcc)
-    {
-        NS_PRECONDITION(xpcc,"bad param");
-        JSContext* cx = xpcc->GetJSContext();
-        Entry* entry = (Entry*)
-            JS_DHashTableOperate(mTable, cx, JS_DHASH_ADD);
-        if(!entry)
-            return nsnull;
-        if(entry->key)
-            return entry->value;
-        entry->key = cx;
-        entry->value = xpcc;
-        return xpcc;
-    }
-
-    inline void Remove(XPCContext* xpcc)
-    {
-        NS_PRECONDITION(xpcc,"bad param");
-        JS_DHashTableOperate(mTable, xpcc->GetJSContext(), JS_DHASH_REMOVE);
-    }
-
-    inline uint32 Count() {return mTable->entryCount;}
-    inline uint32 Enumerate(JSDHashEnumerator f, void *arg)
-        {return JS_DHashTableEnumerate(mTable, f, arg);}
-
-    ~JSContext2XPCContextMap();
-private:
-    JSContext2XPCContextMap();    // no implementation
-    JSContext2XPCContextMap(int size);
-private:
-    JSDHashTable *mTable;
-};
-
 /*************************/
 
 class JSObject2WrappedJSMap
 {
 public:
     struct Entry : public JSDHashEntryHdr
     {
         JSObject*       key;
--- a/js/src/xpconnect/src/xpcmodule.cpp
+++ b/js/src/xpconnect/src/xpcmodule.cpp
@@ -62,17 +62,16 @@ NS_DECL_CLASSINFO(XPCVariant)
     {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_SINGLETON_CONSTRUCTOR(nsIJSRuntimeService, nsJSRuntimeServiceImpl::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)
@@ -81,17 +80,17 @@ NS_DECL_CLASSINFO(nsXPCException)
 #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_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,       nsIJSRuntimeServiceConstructor},
+  {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
   // jsloader stuff
  ,{ "JS component loader", MOZJSCOMPONENTLOADER_CID,
@@ -110,33 +109,31 @@ static const nsModuleComponentInfo compo
 
 static nsresult
 xpcModuleCtor(nsIModule* self)
 {
     nsXPConnect::InitStatics();
     nsXPCException::InitStatics();
     XPCWrappedNativeScope::InitStatics();
     XPCPerThreadData::InitStatics();
-    nsJSRuntimeServiceImpl::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();
-    nsJSRuntimeServiceImpl::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
@@ -437,35 +437,40 @@ private:
 // We have a general rule internally that getters that return addref'd interface
 // pointer generally do so using an 'out' parm. When interface pointers are
 // returned as function call result values they are not addref'd. Exceptions
 // to this rule are noted explicitly.
 
 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 }}
+
 class nsXPConnect : public nsIXPConnect,
                     public nsIThreadObserver,
                     public nsSupportsWeakReference,
                     public nsCycleCollectionJSRuntime,
-                    public nsCycleCollectionParticipant
+                    public nsCycleCollectionParticipant,
+                    public nsIJSRuntimeService
 {
 public:
     // all the interface method declarations...
     NS_DECL_ISUPPORTS
     NS_DECL_NSIXPCONNECT
     NS_DECL_NSITHREADOBSERVER
+    NS_DECL_NSIJSRUNTIMESERVICE
 
     // non-interface implementation
 public:
     // These get non-addref'd pointers
     static nsXPConnect*  GetXPConnect();
-    static XPCJSRuntime* GetRuntime(nsXPConnect* xpc = nsnull);
-    static XPCContext*   GetContext(JSContext* cx, nsXPConnect* xpc = nsnull);
-    static nsIJSRuntimeService* GetJSRuntimeService(nsXPConnect* xpc = nsnull);
+    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);
@@ -540,19 +545,16 @@ public:
 #ifdef XPC_IDISPATCH_SUPPORT
 public:
     static PRBool IsIDispatchEnabled();
 #endif
 protected:
     nsXPConnect();
 
 private:
-    JSBool EnsureRuntime() {return mRuntime ? JS_TRUE : CreateRuntime();}
-    JSBool CreateRuntime();
-
     static PRThread* FindMainThread();
 
 private:
     // Singleton instance
     static nsXPConnect*      gSelf;
     static JSBool            gOnceAliveNowDead;
 
     XPCJSRuntime*            mRuntime;
@@ -572,16 +574,18 @@ private:
     nsCOMPtr<nsIXPCToolsProfiler> mProfiler;
     nsCOMPtr<nsILocalFile>        mProfilerOutputFile;
 #endif
 
 #ifndef XPCONNECT_STANDALONE
     typedef nsBaseHashtable<nsVoidPtrHashKey, nsISupports*, nsISupports*> ScopeSet;
     ScopeSet mScopes;
 #endif
+    nsCOMPtr<nsIXPCScriptable> mBackstagePass;
+
     static PRUint32 gReportAllJSExceptions;
 };
 
 /***************************************************************************/
 
 class XPCRootSetElem
 {
 public:
@@ -612,24 +616,21 @@ private:
 
 // In the current xpconnect system there can only be one XPCJSRuntime.
 // So, xpconnect can only be used on one JSRuntime within the process.
 
 // no virtuals. no refcounting.
 class XPCJSRuntime
 {
 public:
-    static XPCJSRuntime* newXPCJSRuntime(nsXPConnect* aXPConnect,
-                                         nsIJSRuntimeService* aJSRuntimeService);
+    static XPCJSRuntime* newXPCJSRuntime(nsXPConnect* aXPConnect);
 
     JSRuntime*     GetJSRuntime() const {return mJSRuntime;}
     nsXPConnect*   GetXPConnect() const {return mXPConnect;}
 
-    nsIJSRuntimeService* GetJSRuntimeService() const {return mJSRuntimeService;}
-
     JSObject2WrappedJSMap*     GetWrappedJSMap()        const
         {return mWrappedJSMap;}
 
     IID2WrappedJSClassMap*     GetWrappedJSClassMap()   const
         {return mWrappedJSClassMap;}
 
     IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const
         {return mIID2NativeInterfaceMap;}
@@ -652,18 +653,17 @@ public:
     XPCWrappedNativeProtoMap* GetDetachedWrappedNativeProtoMap() const
         {return mDetachedWrappedNativeProtoMap;}
 
     XPCNativeWrapperMap* GetExplicitNativeWrapperMap() const
         {return mExplicitNativeWrapperMap;}
 
     XPCLock* GetMapLock() const {return mMapLock;}
 
-    XPCContext* GetXPCContext(JSContext* cx);
-    XPCContext* SyncXPCContextList(JSContext* cx = nsnull);
+    JSBool OnJSContextNew(JSContext* cx);
 
     JSBool DeferredRelease(nsISupports* obj);
 
     JSBool GetDoingFinalization() const {return mDoingFinalization;}
 
     // Mapping of often used strings to jsid atoms that live 'forever'.
     //
     // To add a new string: add to this list and to XPCJSRuntime::mStrings
@@ -747,36 +747,27 @@ public:
         {XPCAutoLock lock(GetMapLock());
          JS_DHashTableOperate(DEBUG_WrappedNativeHashtable,
                               wrapper, JS_DHASH_REMOVE);}
 private:
    JSDHashTable* DEBUG_WrappedNativeHashtable;
 public:
 #endif
 
-    // For use by XPCWrappedNativeScope.
-    JSContext2XPCContextMap*  GetContextMap() const {return mContextMap;}
-
 private:
     XPCJSRuntime(); // no implementation
-    XPCJSRuntime(nsXPConnect* aXPConnect,
-                 nsIJSRuntimeService* aJSRuntimeService);
-
-    JSBool GenerateStringIDs(JSContext* cx);
-    void PurgeXPCContextList();
+    XPCJSRuntime(nsXPConnect* aXPConnect);
 
 private:
     static const char* mStrings[IDX_TOTAL_COUNT];
     jsid mStrIDs[IDX_TOTAL_COUNT];
     jsval mStrJSVals[IDX_TOTAL_COUNT];
 
     nsXPConnect* mXPConnect;
     JSRuntime*  mJSRuntime;
-    nsIJSRuntimeService* mJSRuntimeService; // hold this to hold the JSRuntime
-    JSContext2XPCContextMap* mContextMap;
     JSObject2WrappedJSMap*   mWrappedJSMap;
     IID2WrappedJSClassMap*   mWrappedJSClassMap;
     IID2NativeInterfaceMap*  mIID2NativeInterfaceMap;
     ClassInfo2NativeSetMap*  mClassInfo2NativeSetMap;
     NativeSetMap*            mNativeSetMap;
     IID2ThisTranslatorMap*   mThisTranslatorMap;
     XPCNativeScriptableSharedMap* mNativeScriptableSharedMap;
     XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
@@ -797,30 +788,29 @@ private:
 /***************************************************************************/
 /***************************************************************************/
 // XPCContext is mostly a dumb class to hold JSContext specific data and
 // maps that let us find wrappers created for the given JSContext.
 
 // no virtuals
 class XPCContext
 {
+    friend class XPCJSRuntime;
 public:
-    static XPCContext* newXPCContext(XPCJSRuntime* aRuntime,
-                                     JSContext* aJSContext);
+    static XPCContext* GetXPCContext(JSContext* aJSContext)
+        {
+            NS_ASSERTION(aJSContext->data2, "should already have XPCContext");
+            return static_cast<XPCContext *>(aJSContext->data2);
+        }
 
     XPCJSRuntime* GetRuntime() const {return mRuntime;}
     JSContext* GetJSContext() const {return mJSContext;}
 
     enum LangType {LANG_UNKNOWN, LANG_JS, LANG_NATIVE};
     
-    // Mark functions used by SyncXPCContextList
-    void Mark()             {mMarked = (JSPackedBool) JS_TRUE;}
-    void Unmark()           {mMarked = (JSPackedBool) JS_FALSE;}
-    JSBool IsMarked() const {return (JSBool) mMarked;}
-
     LangType GetCallingLangType() const
         {
             return mCallingLangType;
         }
     LangType SetCallingLangType(LangType lt)
         {
             LangType tmp = mCallingLangType; 
             mCallingLangType = lt; 
@@ -894,26 +884,27 @@ public:
     void RemoveScope(PRCList *scope) { PR_REMOVE_LINK(scope); }
 
     ~XPCContext();
 
 private:
     XPCContext();    // no implementation
     XPCContext(XPCJSRuntime* aRuntime, JSContext* aJSContext);
 
+    static XPCContext* newXPCContext(XPCJSRuntime* aRuntime,
+                                     JSContext* aJSContext);
 private:
     XPCJSRuntime* mRuntime;
     JSContext*  mJSContext;
     nsresult mLastResult;
     nsresult mPendingResult;
     nsIXPCSecurityManager* mSecurityManager;
     nsIException* mException;
     LangType mCallingLangType;
     PRUint16 mSecurityManagerFlags;
-    JSPackedBool mMarked;
 
     // A linked list of scopes to notify when we are destroyed.
     PRCList mScopes;
 };
 
 /***************************************************************************/
 
 #define NATIVE_CALLER  XPCContext::LANG_NATIVE
@@ -3046,19 +3037,16 @@ public:
 #ifdef DEBUG
     JSBool DEBUG_StackHasJSContext(JSContext*  aJSContext);
 #endif
 
     const nsTArray<XPCJSContextInfo>* GetStack()
     { return &mStack; }
 
 private:
-    void SyncJSContexts();
-
-private:
     nsAutoTArray<XPCJSContextInfo, 16> mStack;
     JSContext*  mSafeJSContext;
 
     // If non-null, we own it; same as mSafeJSContext if SetSafeJSContext
     // not called.
     JSContext*  mOwnSafeJSContext;
 };
 
@@ -3175,25 +3163,16 @@ public:
     void ReleaseNatives();
 
     PRBool IsValid() const {return mJSContextStack != nsnull;}
 
     static PRLock* GetLock() {return gLock;}
     // Must be called with the threads locked.
     static XPCPerThreadData* IterateThreads(XPCPerThreadData** iteratorp);
 
-    XPCContext* GetRecentXPCContext(JSContext* cx) const
-        {return cx == mMostRecentJSContext ? mMostRecentXPCContext : nsnull;}
-
-    void SetRecentContext(JSContext* cx, XPCContext* xpcc)
-        {mMostRecentJSContext = cx; mMostRecentXPCContext = xpcc;}
-
-    void ClearRecentContext()
-        {mMostRecentJSContext = nsnull; mMostRecentXPCContext = nsnull;}
-
     AutoMarkingPtr**  GetAutoRootsAdr() {return &mAutoRoots;}
 
     void TraceJS(JSTracer* trc);
     void MarkAutoRootsAfterJSFinalize();
 
     jsuword GetStackLimit() const { return mStackLimit; }
 
     static void InitStatics()
@@ -3218,19 +3197,16 @@ private:
 
 private:
     XPCJSContextStack*   mJSContextStack;
     XPCPerThreadData*    mNextThread;
     XPCCallContext*      mCallContext;
     jsval                mResolveName;
     XPCWrappedNative*    mResolvingWrapper;
 
-    JSContext*           mMostRecentJSContext;
-    XPCContext*          mMostRecentXPCContext;
-
     nsIExceptionManager* mExceptionManager;
     nsIException*        mException;
     JSBool               mExceptionManagerNotAvailable;
     AutoMarkingPtr*      mAutoRoots;
 
     jsuword              mStackLimit;
 
 #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
@@ -3280,20 +3256,16 @@ private:
         {XPCPerThreadData* data = XPCPerThreadData::GetData(cx);
          return data ? data->GetJSContextStack() : nsnull;}
 
     static nsXPCThreadJSContextStackImpl* gXPCThreadJSContextStack;
     friend class nsXPCJSContextStackIterator;
 };
 
 /***************************************************************************/
-#define NS_JS_RUNTIME_SERVICE_CID \
-{0xb5e65b52, 0x1dd1, 0x11b2, \
-    { 0xae, 0x8f, 0xf0, 0x92, 0x8e, 0xd8, 0x84, 0x82 }}
-
 #ifndef XPCONNECT_STANDALONE
 #include "nsIScriptSecurityManager.h"
 
 class BackstagePass : public nsIScriptObjectPrincipal,
                       public nsIXPCScriptable,
                       public nsIClassInfo
 {
 public:
@@ -3348,17 +3320,16 @@ class nsJSRuntimeServiceImpl : public ns
 
     static void FreeSingleton();
 
     nsJSRuntimeServiceImpl();
     virtual ~nsJSRuntimeServiceImpl();
 
     static void InitStatics() { gJSRuntimeService = nsnull; }
  protected:
-    JSRuntime *mRuntime;
     static nsJSRuntimeServiceImpl* gJSRuntimeService;
     nsCOMPtr<nsIXPCScriptable> mBackstagePass;
 };
 
 /***************************************************************************/
 // 'Components' object
 
 class nsXPCComponents : public nsIXPCComponents,
--- a/js/src/xpconnect/src/xpcruntimesvc.cpp
+++ b/js/src/xpconnect/src/xpcruntimesvc.cpp
@@ -173,131 +173,8 @@ BackstagePass::GetFlags(PRUint32 *aFlags
 }
 
 /* [notxpcom] readonly attribute nsCID classIDNoAlloc; */
 NS_IMETHODIMP 
 BackstagePass::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
-
-/*
- * This object holds state that we don't want to lose!
- *
- * The plan is that once created this object never goes away. We do an
- * intentional extra addref at construction to keep it around even if no one
- * is using it.
- */
-
-nsJSRuntimeServiceImpl::nsJSRuntimeServiceImpl() :
-    mRuntime(0)
-{
-}
-
-nsJSRuntimeServiceImpl::~nsJSRuntimeServiceImpl() {
-    if(mRuntime)
-    {
-        JS_DestroyRuntime(mRuntime);
-        JS_ShutDown();
-#ifdef DEBUG_shaver_off
-        fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mRuntime);
-#endif
-    }
-
-    XPCPerThreadData::ShutDown();
-}
-
-NS_IMPL_THREADSAFE_ISUPPORTS2(nsJSRuntimeServiceImpl,
-                              nsIJSRuntimeService,
-                              nsISupportsWeakReference)
-
-nsJSRuntimeServiceImpl*
-nsJSRuntimeServiceImpl::gJSRuntimeService = nsnull;
-
-nsJSRuntimeServiceImpl*
-nsJSRuntimeServiceImpl::GetSingleton()
-{
-    if(!gJSRuntimeService)
-    {
-        gJSRuntimeService = new nsJSRuntimeServiceImpl();
-        // hold an extra reference to lock it down
-        NS_IF_ADDREF(gJSRuntimeService);
-
-    }
-    NS_IF_ADDREF(gJSRuntimeService);
-
-    return gJSRuntimeService;
-}
-
-void
-nsJSRuntimeServiceImpl::FreeSingleton()
-{
-    NS_IF_RELEASE(gJSRuntimeService);
-}
-
-const uint32 gGCSize = 32L * 1024L * 1024L; /* pref? */
-
-/* attribute JSRuntime runtime; */
-NS_IMETHODIMP
-nsJSRuntimeServiceImpl::GetRuntime(JSRuntime **runtime)
-{
-    if(!runtime)
-        return NS_ERROR_NULL_POINTER;
-
-    if(!mRuntime)
-    {
-        // Call XPCPerThreadData::GetData to initialize 
-        // XPCPerThreadData::gTLSIndex before initializing 
-        // JSRuntime::threadTPIndex in JS_NewRuntime.
-        //
-        // XPConnect uses a thread local storage (XPCPerThreadData) indexed by
-        // XPCPerThreadData::gTLSIndex, and SpiderMonkey GC uses a thread local 
-        // storage indexed by JSRuntime::threadTPIndex.
-        //
-        // The destructor for XPCPerThreadData::gTLSIndex may access 
-        // thread local storage indexed by JSRuntime::threadTPIndex. 
-        // Thus, the destructor for JSRuntime::threadTPIndex must be called 
-        // later than the one for XPCPerThreadData::gTLSIndex.
-        //
-        // We rely on the implementation of NSPR that calls destructors at 
-        // the same order of calling PR_NewThreadPrivateIndex.
-        XPCPerThreadData::GetData(nsnull);
-        
-        mRuntime = JS_NewRuntime(gGCSize);
-        if(!mRuntime)
-            return NS_ERROR_OUT_OF_MEMORY;
-
-        // Unconstrain the runtime's threshold on nominal heap size, to avoid
-        // triggering GC too often if operating continuously near an arbitrary
-        // finite threshold (0xffffffff is infinity for uint32 parameters).
-        // This leaves the maximum-JS_malloc-bytes threshold still in effect
-        // to cause period, and we hope hygienic, last-ditch GCs from within
-        // the GC's allocator.
-        JS_SetGCParameter(mRuntime, JSGC_MAX_BYTES, 0xffffffff);
-    }
-    *runtime = mRuntime;
-    return NS_OK;
-}
-
-/* attribute nsIXPCScriptable backstagePass; */
-NS_IMETHODIMP
-nsJSRuntimeServiceImpl::GetBackstagePass(nsIXPCScriptable **bsp)
-{
-    if(!mBackstagePass) {
-#ifndef XPCONNECT_STANDALONE
-        nsCOMPtr<nsIPrincipal> sysprin;
-        nsCOMPtr<nsIScriptSecurityManager> secman = 
-            do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
-        if(!secman)
-            return NS_ERROR_NOT_AVAILABLE;
-        if(NS_FAILED(secman->GetSystemPrincipal(getter_AddRefs(sysprin))))
-            return NS_ERROR_NOT_AVAILABLE;
-        
-        mBackstagePass = new BackstagePass(sysprin);
-#else
-        mBackstagePass = new BackstagePass();
-#endif
-        if(!mBackstagePass)
-            return NS_ERROR_OUT_OF_MEMORY;
-    }
-    NS_ADDREF(*bsp = mBackstagePass);
-    return NS_OK;
-}
--- a/js/src/xpconnect/src/xpcthreadcontext.cpp
+++ b/js/src/xpconnect/src/xpcthreadcontext.cpp
@@ -55,28 +55,19 @@ XPCJSContextStack::XPCJSContextStack()
 
 XPCJSContextStack::~XPCJSContextStack()
 {
     if(mOwnSafeJSContext)
     {
         JS_SetContextThread(mOwnSafeJSContext);
         JS_DestroyContext(mOwnSafeJSContext);
         mOwnSafeJSContext = nsnull;
-        SyncJSContexts();
     }
 }
 
-void
-XPCJSContextStack::SyncJSContexts()
-{
-    nsXPConnect* xpc = nsXPConnect::GetXPConnect();
-    if(xpc)
-        xpc->SyncJSContexts();
-}
-
 /* readonly attribute PRInt32 count; */
 NS_IMETHODIMP
 XPCJSContextStack::GetCount(PRInt32 *aCount)
 {
     *aCount = mStack.Length();
     return NS_OK;
 }
 
@@ -269,17 +260,16 @@ NS_IMETHODIMP
 XPCJSContextStack::SetSafeJSContext(JSContext * aSafeJSContext)
 {
     if(mOwnSafeJSContext &&
        mOwnSafeJSContext == mSafeJSContext &&
        mOwnSafeJSContext != aSafeJSContext)
     {
         JS_DestroyContextNoGC(mOwnSafeJSContext);
         mOwnSafeJSContext = nsnull;
-        SyncJSContexts();
     }
 
     mSafeJSContext = aSafeJSContext;
     return NS_OK;
 }
 
 /***************************************************************************/
 
@@ -461,18 +451,16 @@ GetThreadStackLimit()
 }
 
 XPCPerThreadData::XPCPerThreadData()
     :   mJSContextStack(new XPCJSContextStack()),
         mNextThread(nsnull),
         mCallContext(nsnull),
         mResolveName(0),
         mResolvingWrapper(nsnull),
-        mMostRecentJSContext(nsnull),
-        mMostRecentXPCContext(nsnull),
         mExceptionManager(nsnull),
         mException(nsnull),
         mExceptionManagerNotAvailable(JS_FALSE),
         mAutoRoots(nsnull),
         mStackLimit(GetThreadStackLimit())
 #ifdef XPC_CHECK_WRAPPER_THREADSAFETY
       , mWrappedNativeThreadsafetyReportDepth(0)
 #endif
--- a/js/src/xpconnect/src/xpcvariant.cpp
+++ b/js/src/xpconnect/src/xpcvariant.cpp
@@ -66,17 +66,17 @@ XPCTraceableVariant::~XPCTraceableVarian
     NS_ASSERTION(JSVAL_IS_GCTHING(mJSVal), "Must be traceable or unlinked");
 
     // If mJSVal is JSVAL_STRING, we don't need to clean anything up;
     // simply removing the string from the root set is good.
     if(!JSVAL_IS_STRING(mJSVal))
         nsVariant::Cleanup(&mData);
 
     if(!JSVAL_IS_NULL(mJSVal))
-        RemoveFromRootSet(nsXPConnect::GetRuntime()->GetJSRuntime());
+        RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
 }
 
 void XPCTraceableVariant::TraceJS(JSTracer* trc)
 {
     NS_ASSERTION(JSVAL_IS_TRACEABLE(mJSVal), "Must be traceable");
     JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0);
     JS_CallTracer(trc, JSVAL_TO_TRACEABLE(mJSVal), JSVAL_TRACE_KIND(mJSVal));
 }
@@ -103,17 +103,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XP
     // so Cleanup() won't try to delete it
     if(JSVAL_IS_STRING(tmp->mJSVal))
         tmp->mData.u.wstr.mWStringValue = nsnull;
     nsVariant::Cleanup(&tmp->mData);
 
     if(JSVAL_IS_TRACEABLE(tmp->mJSVal))
     {
         XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp);
-        v->RemoveFromRootSet(nsXPConnect::GetRuntime()->GetJSRuntime());
+        v->RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
     }
     tmp->mJSVal = JSVAL_NULL;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 // static 
 XPCVariant* XPCVariant::newVariant(XPCCallContext& ccx, jsval aJSVal)
 {
     XPCVariant* variant;
--- a/js/src/xpconnect/src/xpcwrappedjs.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjs.cpp
@@ -88,17 +88,17 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrapp
         cb.NoteXPCOMChild(static_cast<nsIXPConnectWrappedJS*>(root));
 
     return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsXPCWrappedJS)
     if(tmp->mRoot && !tmp->mRoot->HasWeakReferences() && tmp->IsValid())
     {
-        XPCJSRuntime* rt = nsXPConnect::GetRuntime();
+        XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
         if(rt)
         {
             if(tmp->mRoot == tmp)
             {
                 // remove this root wrapper from the map
                 JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
                 if(map)
                 {
@@ -224,32 +224,33 @@ nsXPCWrappedJS::AddRef(void)
 
 nsrefcnt
 nsXPCWrappedJS::Release(void)
 {
     NS_PRECONDITION(0 != mRefCnt, "dup release");
 
     // need to take the map lock here to prevent GetNewOrUsed from trying
     // to reuse a wrapper on one thread while it's being destroyed on another
-    XPCAutoLock lock(nsXPConnect::GetRuntime()->GetMapLock());
+    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
+    XPCAutoLock lock(rt->GetMapLock());
 
 do_decrement:
 
     nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt);
     NS_LOG_RELEASE(this, cnt, "nsXPCWrappedJS");
 
     if(0 == cnt)
     {
         NS_DELETEXPCOM(this);   // also unlinks us from chain
         return 0;
     }
     if(1 == cnt)
     {
         if(IsValid())
-            RemoveFromRootSet(nsXPConnect::GetRuntime()->GetJSRuntime());
+            RemoveFromRootSet(rt->GetJSRuntime());
 
         // If we are not the root wrapper or if we are not being used from a
         // weak reference, then this extra ref is not needed and we can let
         // ourself be deleted.
         // Note: HasWeakReferences() could only return true for the root.
         if(!HasWeakReferences())
             goto do_decrement;
     }
@@ -452,25 +453,22 @@ nsXPCWrappedJS::~nsXPCWrappedJS()
     NS_PRECONDITION(0 == mRefCnt, "refcounting error");
 
     if(mRoot == this)
     {
         // Let the nsWeakReference object (if present) know of our demise.
         ClearWeakReferences();
 
         // Remove this root wrapper from the map
-        XPCJSRuntime* rt = nsXPConnect::GetRuntime();
-        if(rt)
+        XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
+        JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
+        if(map)
         {
-            JSObject2WrappedJSMap* map = rt->GetWrappedJSMap();
-            if(map)
-            {
-                XPCAutoLock lock(rt->GetMapLock());
-                map->Remove(this);
-            }
+            XPCAutoLock lock(rt->GetMapLock());
+            map->Remove(this);
         }
     }
     Unlink();
 }
 
 void
 nsXPCWrappedJS::Unlink()
 {
@@ -490,18 +488,18 @@ nsXPCWrappedJS::Unlink()
         }
         // let the root go
         NS_RELEASE(mRoot);
     }
 
     NS_IF_RELEASE(mClass);
     if (mOuter)
     {
-        XPCJSRuntime* rt = nsXPConnect::GetRuntime();
-        if (rt && rt->GetThreadRunningGC())
+        XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
+        if (rt->GetThreadRunningGC())
         {
             rt->DeferredRelease(mOuter);
             mOuter = nsnull;
         }
         else
         {
             NS_RELEASE(mOuter);
         }
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -186,20 +186,17 @@ static void DEBUG_TrackNewWrapper(XPCWra
             DEBUG_MaxWrappedNativeNoProtoCount = DEBUG_LiveWrappedNativeNoProtoCount;
     }
 #endif
 }
 
 static void DEBUG_TrackDeleteWrapper(XPCWrappedNative* wrapper)
 {
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
-    if(nsXPConnect::GetRuntime())
-        nsXPConnect::GetRuntime()->DEBUG_RemoveWrappedNative(wrapper);
-    else
-        NS_ERROR("failed to remove wrapper");
+    nsXPConnect::GetRuntimeInstance()->DEBUG_RemoveWrappedNative(wrapper);
 #endif
 #ifdef XPC_TRACK_WRAPPER_STATS
     DEBUG_TotalLiveWrappedNativeCount--;
     if(wrapper->HasProto())
         DEBUG_LiveWrappedNativeWithProtoCount--;
     else
         DEBUG_LiveWrappedNativeNoProtoCount--;
 
@@ -3392,17 +3389,17 @@ XPCJSObjectHolder::GetJSObject(JSObject*
 XPCJSObjectHolder::XPCJSObjectHolder(XPCCallContext& ccx, JSObject* obj)
     : mJSObj(obj)
 {
     ccx.GetRuntime()->AddObjectHolderRoot(this);
 }
 
 XPCJSObjectHolder::~XPCJSObjectHolder()
 {
-    RemoveFromRootSet(nsXPConnect::GetRuntime()->GetJSRuntime());
+    RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetJSRuntime());
 }
 
 void
 XPCJSObjectHolder::TraceJS(JSTracer *trc)
 {
     JS_SET_TRACING_DETAILS(trc, PrintTraceName, this, 0);
     JS_CallTracer(trc, mJSObj, JSTRACE_OBJECT);
 }
--- a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
@@ -740,21 +740,19 @@ out:
 
     return set;
 }
 
 // static 
 void 
 XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
 {
-    XPCJSRuntime* rt;
-    ClassInfo2NativeSetMap* map;
-    
-    if(nsnull != (rt = nsXPConnect::GetRuntime()) && 
-       nsnull != (map = rt->GetClassInfo2NativeSetMap()))
+    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
+    ClassInfo2NativeSetMap* map = rt->GetClassInfo2NativeSetMap();
+    if(map)
     {   // scoped lock
         XPCAutoLock lock(rt->GetMapLock());
         map->Remove(classInfo);
     }
 }
 
 // static
 XPCNativeSet*
--- a/js/src/xpconnect/src/xpcwrappednativescope.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp
@@ -154,19 +154,17 @@ XPCWrappedNativeScope::XPCWrappedNativeS
         for(XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
             NS_ASSERTION(aGlobal != cur->GetGlobalJSObject(), "dup object");
 #endif
 
         mNext = gScopes;
         gScopes = this;
 
         // Grab the XPCContext associated with our context.
-        mContext = mRuntime->GetContextMap()->Find(ccx.GetJSContext());
-        NS_ASSERTION(mContext, "Context map is not synchronized");
-
+        mContext = XPCContext::GetXPCContext(ccx.GetJSContext());
         mContext->AddScope(this);
     }
 
     if(aGlobal)
         SetGlobal(ccx, aGlobal);
 
     DEBUG_TrackNewScope(this);
     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
@@ -488,19 +486,17 @@ XPCWrappedNativeScope::FinishedMarkPhase
         cur = next;
     }
 }
 
 // static
 void
 XPCWrappedNativeScope::FinishedFinalizationPhaseOfGC(JSContext* cx)
 {
-    XPCJSRuntime* rt = nsXPConnect::GetRuntime();
-    if(!rt)
-        return;
+    XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
 
     // FIXME The lock may not be necessary since we are inside
     // JSGC_FINALIZE_END callback and at this point GC still serializes access
     // to JS runtime. See bug 380139.
     XPCAutoLock lock(rt->GetMapLock());
     KillDyingScopes();
 }
 
--- a/js/src/xpconnect/tests/TestXPC.cpp
+++ b/js/src/xpconnect/tests/TestXPC.cpp
@@ -766,17 +766,16 @@ int main()
 
         if(NS_FAILED(cxstack->Pop(nsnull)))
             DIE("FAILED to pop the current jscontext from the nsThreadJSContextStack service!\n");
 
         JS_ClearScope(jscontext, glob);
         JS_GC(jscontext);
         JS_GC(jscontext);
         JS_DestroyContext(jscontext);
-        xpc->SyncJSContexts();
         xpc->DebugDump(4);
 
         cxstack = nsnull;   // release service held by nsCOMPtr
         xpc     = nsnull;   // release service held by nsCOMPtr
         rtsvc   = nsnull;   // release service held by nsCOMPtr
     }
     rv = NS_ShutdownXPCOM( NULL );
     NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM FAILED");