bug 718600 - remove JSRuntime::(rtLock, state). r=luke
authorIgor Bukanov <igor@mir2.org>
Tue, 17 Jan 2012 23:14:49 +0100
changeset 84792 9519fed510ee714348ebb4bbdafb22d7d5814240
parent 84778 715e4b7e3b51fded840bec05b9294cc9b8506feb
child 84793 2813a0ddc819fb89f977bb8d7636e74a10248001
push id21879
push usermak77@bonardo.net
push dateThu, 19 Jan 2012 10:34:58 +0000
treeherdermozilla-central@f76b576a9e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs718600
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 718600 - remove JSRuntime::(rtLock, state). r=luke
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsfriendapi.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jslock.cpp
js/src/jslock.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -211,17 +211,17 @@ JS_PUBLIC_API(jsval)
 JS_GetEmptyStringValue(JSContext *cx)
 {
     return STRING_TO_JSVAL(cx->runtime->emptyString);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_GetEmptyString(JSRuntime *rt)
 {
-    JS_ASSERT(rt->state == JSRTS_UP);
+    JS_ASSERT(rt->hasContexts());
     return rt->emptyString;
 }
 
 static JSBool
 TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
 {
     const char *format;
     JSArgumentFormatMap *map;
@@ -675,17 +675,16 @@ JS_IsBuiltinFunctionConstructor(JSFuncti
  * Has a new runtime ever been created?  This flag is used to detect unsafe
  * changes to js_CStringsAreUTF8 after a runtime has been created, and to
  * control things that should happen only once across all runtimes.
  */
 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
 
 JSRuntime::JSRuntime()
   : atomsCompartment(NULL),
-    state(),
     cxCallback(NULL),
     compartmentCallback(NULL),
     activityCallback(NULL),
     activityCallbackArg(NULL),
     gcSystemAvailableChunkListHead(NULL),
     gcUserAvailableChunkListHead(NULL),
     gcKeepAtoms(0),
     gcBytes(0),
@@ -734,21 +733,16 @@ JSRuntime::JSRuntime()
     data(NULL),
 #ifdef JS_THREADSAFE
     gcLock(NULL),
     gcDone(NULL),
     requestDone(NULL),
     requestCount(0),
     gcThread(NULL),
     gcHelperThread(thisFromCtor()),
-    rtLock(NULL),
-# ifdef DEBUG
-    rtLockOwner(0),
-# endif
-    stateChange(NULL),
 #endif
     debuggerMutations(0),
     securityCallbacks(NULL),
     structuredCloneCallbacks(NULL),
     telemetryCallback(NULL),
     propertyRemovals(0),
     scriptFilenameTable(NULL),
 #ifdef JS_THREADSAFE
@@ -806,22 +800,16 @@ JSRuntime::init(uint32_t maxbytes)
         return false;
 
     wrapObjectCallback = js::TransparentObjectWrapper;
 
 #ifdef JS_THREADSAFE
     /* this is asymmetric with JS_ShutDown: */
     if (!js_SetupLocks(8, 16))
         return false;
-    rtLock = JS_NEW_LOCK();
-    if (!rtLock)
-        return false;
-    stateChange = JS_NEW_CONDVAR(gcLock);
-    if (!stateChange)
-        return false;
 #endif
 
     debugMode = false;
     if (!js_InitThreads(this))
         return false;
     if (!InitRuntimeNumberState(this))
         return false;
 
@@ -854,20 +842,16 @@ JSRuntime::~JSRuntime()
     js_FinishGC(this);
 #ifdef JS_THREADSAFE
     if (gcLock)
         JS_DESTROY_LOCK(gcLock);
     if (gcDone)
         JS_DESTROY_CONDVAR(gcDone);
     if (requestDone)
         JS_DESTROY_CONDVAR(requestDone);
-    if (rtLock)
-        JS_DESTROY_LOCK(rtLock);
-    if (stateChange)
-        JS_DESTROY_CONDVAR(stateChange);
 #endif
 }
 
 #ifdef JS_THREADSAFE
 void
 JSRuntime::setOwnerThread()
 {
     JS_ASSERT(ownerThread_ == (void *)-1);
@@ -1132,28 +1116,16 @@ JS_IsInRequest(JSContext *cx)
 #ifdef JS_THREADSAFE
     JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread()));
     return JS_THREAD_DATA(cx)->requestDepth != 0;
 #else
     return false;
 #endif
 }
 
-JS_PUBLIC_API(void)
-JS_Lock(JSRuntime *rt)
-{
-    JS_LOCK_RUNTIME(rt);
-}
-
-JS_PUBLIC_API(void)
-JS_Unlock(JSRuntime *rt)
-{
-    JS_UNLOCK_RUNTIME(rt);
-}
-
 JS_PUBLIC_API(JSContextCallback)
 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback)
 {
     JSContextCallback old;
 
     old = rt->cxCallback;
     rt->cxCallback = cxCallback;
     return old;
@@ -1922,18 +1894,17 @@ JS_ResolveStandardClass(JSContext *cx, J
     RootObject objRoot(cx, &obj);
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     *resolved = JS_FALSE;
 
     rt = cx->runtime;
-    JS_ASSERT(rt->state != JSRTS_DOWN);
-    if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id))
+    if (!rt->hasContexts() || !JSID_IS_ATOM(id))
         return JS_TRUE;
 
     idstr = JSID_TO_STRING(id);
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
     if (idstr == atom) {
         *resolved = JS_TRUE;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2444,22 +2444,16 @@ class JSAutoCheckRequest {
     JSContext *mContext;
 #endif
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 JS_BEGIN_EXTERN_C
 #endif
 
-extern JS_PUBLIC_API(void)
-JS_Lock(JSRuntime *rt);
-
-extern JS_PUBLIC_API(void)
-JS_Unlock(JSRuntime *rt);
-
 extern JS_PUBLIC_API(JSContextCallback)
 JS_SetContextCallback(JSRuntime *rt, JSContextCallback cxCallback);
 
 extern JS_PUBLIC_API(JSContext *)
 JS_NewContext(JSRuntime *rt, size_t stackChunkSize);
 
 extern JS_PUBLIC_API(void)
 JS_DestroyContext(JSContext *cx);
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -450,40 +450,17 @@ js_NewContext(JSRuntime *rt, size_t stac
         return NULL;
     }
 #endif
 
     /*
      * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
      * the GC is not running on another thread.
      */
-    bool first;
-    for (;;) {
-        if (rt->state == JSRTS_UP) {
-            JS_ASSERT(!JS_CLIST_IS_EMPTY(&rt->contextList));
-            first = false;
-            break;
-        }
-        if (rt->state == JSRTS_DOWN) {
-            JS_ASSERT(JS_CLIST_IS_EMPTY(&rt->contextList));
-            first = true;
-            rt->state = JSRTS_LAUNCHING;
-            break;
-        }
-        JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
-
-        /*
-         * During the above wait after we are notified about the state change
-         * but before we wake up, another thread could enter the GC from
-         * js_DestroyContext, bug 478336. So we must wait here to ensure that
-         * when we exit the loop with the first flag set to true, that GC is
-         * finished.
-         */
-        js_WaitForGC(rt);
-    }
+    bool first = JS_CLIST_IS_EMPTY(&rt->contextList);
     JS_APPEND_LINK(&cx->link, &rt->contextList);
     JS_UNLOCK_GC(rt);
 
     js_InitRandom(cx);
 
     /*
      * If cx is the first context on this runtime, initialize well-known atoms,
      * keywords, numbers, and strings.  If one of these steps should fail, the
@@ -502,20 +479,16 @@ js_NewContext(JSRuntime *rt, size_t stac
 
 #ifdef JS_THREADSAFE
         JS_EndRequest(cx);
 #endif
         if (!ok) {
             js_DestroyContext(cx, JSDCM_NEW_FAILED);
             return NULL;
         }
-
-        AutoLockGC lock(rt);
-        rt->state = JSRTS_UP;
-        JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
     }
 
     JSContextCallback cxCallback = rt->cxCallback;
     if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
         js_DestroyContext(cx, JSDCM_NEW_FAILED);
         return NULL;
     }
 
@@ -524,17 +497,16 @@ js_NewContext(JSRuntime *rt, size_t stac
 
 void
 js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
 {
     JSRuntime *rt = cx->runtime;
     JS_AbortIfWrongThread(rt);
 
     JSContextCallback cxCallback;
-    JSBool last;
 
     JS_ASSERT(!cx->enumerators);
 
 #ifdef JS_THREADSAFE
     /*
      * For API compatibility we allow to destroy contexts without a thread in
      * optimized builds. We assume that the embedding knows that an OOM error
      * cannot happen in JS_SetContextThread.
@@ -560,29 +532,26 @@ js_DestroyContext(JSContext *cx, JSDestr
              * return true.
              */
             DebugOnly<JSBool> callbackStatus = cxCallback(cx, JSCONTEXT_DESTROY);
             JS_ASSERT(callbackStatus);
         }
     }
 
     JS_LOCK_GC(rt);
-    JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
 #ifdef JS_THREADSAFE
     /*
      * Typically we are called outside a request, so ensure that the GC is not
      * running before removing the context from rt->contextList, see bug 477021.
      */
     if (cx->thread()->data.requestDepth == 0)
         js_WaitForGC(rt);
 #endif
     JS_REMOVE_LINK(&cx->link);
-    last = (rt->contextList.next == &rt->contextList);
-    if (last)
-        rt->state = JSRTS_LANDING;
+    bool last = !rt->hasContexts();
     if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC
 #ifdef JS_THREADSAFE
         || cx->outstandingRequests != 0
 #endif
         ) {
         JS_ASSERT(!rt->gcRunning);
 
 #ifdef JS_THREADSAFE
@@ -590,22 +559,17 @@ js_DestroyContext(JSContext *cx, JSDestr
 #endif
         JS_UNLOCK_GC(rt);
 
         if (last) {
 #ifdef JS_THREADSAFE
             /*
              * If this thread is not in a request already, begin one now so
              * that we wait for any racing GC started on a not-last context to
-             * finish, before we plow ahead and unpin atoms. Note that even
-             * though we begin a request here if necessary, we end all
-             * thread's requests before forcing a final GC. This lets any
-             * not-last context destruction racing in another thread try to
-             * force or maybe run the GC, but by that point, rt->state will
-             * not be JSRTS_UP, and that GC attempt will return early.
+             * finish, before we plow ahead and unpin atoms.
              */
             if (cx->thread()->data.requestDepth == 0)
                 JS_BeginRequest(cx);
 #endif
 
             /*
              * Dump remaining type inference results first. This printing
              * depends on atoms still existing.
@@ -621,34 +585,26 @@ js_DestroyContext(JSContext *cx, JSDestr
 
             /* Clear debugging state to remove GC roots. */
             for (CompartmentsIter c(rt); !c.done(); c.next())
                 c->clearTraps(cx);
             JS_ClearAllWatchPoints(cx);
         }
 
 #ifdef JS_THREADSAFE
-        /*
-         * Destroying a context implicitly calls JS_EndRequest().  Also, we must
-         * end our request here in case we are "last" -- in that event, another
-         * js_DestroyContext that was not last might be waiting in the GC for our
-         * request to end.  We'll let it run below, just before we do the truly
-         * final GC and then free atom state.
-         */
+        /* Destroying a context implicitly calls JS_EndRequest(). */
         while (cx->outstandingRequests != 0)
             JS_EndRequest(cx);
 #endif
 
         if (last) {
-            js_GC(cx, NULL, GC_LAST_CONTEXT, gcstats::LASTCONTEXT);
+            js_GC(cx, NULL, GC_NORMAL, gcstats::LASTCONTEXT);
 
             /* Take the runtime down, now that it has no contexts or atoms. */
             JS_LOCK_GC(rt);
-            rt->state = JSRTS_DOWN;
-            JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
         } else {
             if (mode == JSDCM_FORCE_GC)
                 js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT);
             else if (mode == JSDCM_MAYBE_GC)
                 JS_MaybeGC(cx);
 
             JS_LOCK_GC(rt);
             js_WaitForGC(rt);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -320,23 +320,16 @@ js_ClearContextThread(JSContext *cx);
 
 typedef enum JSDestroyContextMode {
     JSDCM_NO_GC,
     JSDCM_MAYBE_GC,
     JSDCM_FORCE_GC,
     JSDCM_NEW_FAILED
 } JSDestroyContextMode;
 
-typedef enum JSRuntimeState {
-    JSRTS_DOWN,
-    JSRTS_LAUNCHING,
-    JSRTS_UP,
-    JSRTS_LANDING
-} JSRuntimeState;
-
 typedef struct JSPropertyTreeEntry {
     JSDHashEntryHdr     hdr;
     js::Shape           *child;
 } JSPropertyTreeEntry;
 
 namespace js {
 
 typedef Vector<ScriptOpcodeCountsPair, 0, SystemAllocPolicy> ScriptOpcodeCountsVector;
@@ -346,19 +339,16 @@ typedef Vector<ScriptOpcodeCountsPair, 0
 struct JSRuntime
 {
     /* Default compartment. */
     JSCompartment       *atomsCompartment;
 
     /* List of compartments (protected by the GC lock). */
     js::CompartmentVector compartments;
 
-    /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
-    JSRuntimeState      state;
-
     /* See comment for JS_AbortIfWrongThread in jsapi.h. */
 #ifdef JS_THREADSAFE
   public:
     void clearOwnerThread();
     void setOwnerThread();
     JS_FRIEND_API(bool) onOwnerThread() const;
   private:
     void                *ownerThread_;
@@ -527,16 +517,20 @@ struct JSRuntime
     js::Value           negativeInfinityValue;
     js::Value           positiveInfinityValue;
 
     JSAtom              *emptyString;
 
     /* List of active contexts sharing this runtime; protected by gcLock. */
     JSCList             contextList;
 
+    bool hasContexts() const {
+        return !JS_CLIST_IS_EMPTY(&contextList);
+    }
+    
     /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
     JSDebugHooks        globalDebugHooks;
 
     /* If true, new compartments are initially in debug mode. */
     bool                debugMode;
 
     /* If true, new scripts must be created with PC counter information. */
     bool                profilingScripts;
@@ -558,25 +552,16 @@ struct JSRuntime
     PRLock              *gcLock;
     PRCondVar           *gcDone;
     PRCondVar           *requestDone;
     uint32_t            requestCount;
     JSThread            *gcThread;
 
     js::GCHelperThread  gcHelperThread;
 
-    /* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
-    PRLock              *rtLock;
-#ifdef DEBUG
-    void *              rtLockOwner;
-#endif
-
-    /* Used to synchronize down/up state change; protected by gcLock. */
-    PRCondVar           *stateChange;
-
     /*
      * Mapping from NSPR thread identifiers to JSThreads.
      *
      * This map can be accessed by the GC thread; or by the thread that holds
      * gcLock, if GC is not running.
      */
     JSThread::Map       threads;
 #endif /* JS_THREADSAFE */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -55,17 +55,17 @@ JS_SetGrayGCRootsTracer(JSRuntime *rt, J
 {
     rt->gcGrayRootsTraceOp = traceOp;
     rt->gcGrayRootsData = data;
 }
 
 JS_FRIEND_API(JSString *)
 JS_GetAnonymousString(JSRuntime *rt)
 {
-    JS_ASSERT(rt->state == JSRTS_UP);
+    JS_ASSERT(rt->hasContexts());
     return rt->atomState.anonymousAtom;
 }
 
 JS_FRIEND_API(JSObject *)
 JS_FindCompilationScope(JSContext *cx, JSObject *obj)
 {
     /*
      * We unwrap wrappers here. This is a little weird, but it's what's being
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2098,17 +2098,17 @@ MarkWeakReferences(GCMarker *gcmarker)
 
 namespace JS {
 
 void
 MarkRuntime(JSTracer *trc)
 {
     JSRuntime *rt = trc->runtime;
 
-    if (rt->state != JSRTS_LANDING)
+    if (rt->hasContexts())
         MarkConservativeStackRoots(trc);
 
     for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront())
         gc_root_traversal(trc, r.front());
 
     for (GCLocks::Range r = rt->gcLocksHash.all(); !r.empty(); r.popFront())
         gc_lock_traversal(r.front(), trc);
 
@@ -2654,17 +2654,17 @@ SweepCompartments(JSContext *cx, JSGCInv
     JSCompartment **write = read;
     JS_ASSERT(rt->compartments.length() >= 1);
     JS_ASSERT(*rt->compartments.begin() == rt->atomsCompartment);
 
     while (read < end) {
         JSCompartment *compartment = *read++;
 
         if (!compartment->hold &&
-            (compartment->arenas.arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT))
+            (compartment->arenas.arenaListsAreEmpty() || !rt->hasContexts()))
         {
             compartment->arenas.checkEmptyFreeLists();
             if (callback)
                 JS_ALWAYS_TRUE(callback(cx, compartment, JSCOMPARTMENT_DESTROY));
             if (compartment->principals)
                 JSPRINCIPALS_DROP(cx, compartment->principals);
             cx->delete_(compartment);
             continue;
@@ -3045,17 +3045,16 @@ AutoGCSession::~AutoGCSession()
  * to ensure that the bottom of the stack with possible GC roots recorded in
  * js_GC excludes any pointers we use during the marking implementation.
  */
 static JS_NEVER_INLINE void
 GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
 {
     JSRuntime *rt = cx->runtime;
 
-    JS_ASSERT_IF(comp, gckind != GC_LAST_CONTEXT);
     JS_ASSERT_IF(comp, comp != rt->atomsCompartment);
     JS_ASSERT_IF(comp, rt->gcMode == JSGC_MODE_COMPARTMENT);
 
     /*
      * Recursive GC is no-op and a call from another thread waits the started
      * GC cycle to finish.
      */
     if (rt->gcMarkAndSweep) {
@@ -3072,20 +3071,18 @@ GCCycle(JSContext *cx, JSCompartment *co
     AutoGCSession gcsession(cx);
 
     /*
      * Don't GC if any thread is reporting an OOM. We check the flag after we
      * have set up the GC session and know that the thread that reported OOM
      * is either the current thread or waits for the GC to complete on this
      * thread.
      */
-    if (rt->inOOMReport) {
-        JS_ASSERT(gckind != GC_LAST_CONTEXT);
+    if (rt->inOOMReport)
         return;
-    }
 
     /*
      * We should not be depending on cx->compartment in the GC, so set it to
      * NULL to look for violations.
      */
     SwitchToCompartment sc(cx, (JSCompartment *)NULL);
 
     JS_ASSERT(!rt->gcCurrentCompartment);
@@ -3097,20 +3094,18 @@ GCCycle(JSContext *cx, JSCompartment *co
     /*
      * As we about to purge caches and clear the mark bits we must wait for
      * any background finalization to finish. We must also wait for the
      * background allocation to finish so we can avoid taking the GC lock
      * when manipulating the chunks during the GC.
      */
     JS_ASSERT(!cx->gcBackgroundFree);
     rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
-    if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
-        if (rt->gcHelperThread.prepareForBackgroundSweep())
-            cx->gcBackgroundFree = &rt->gcHelperThread;
-    }
+    if (rt->hasContexts() && rt->gcHelperThread.prepareForBackgroundSweep())
+        cx->gcBackgroundFree = &rt->gcHelperThread;
 #endif
 
     MarkAndSweep(cx, gckind);
 
     if (!comp)
         js_PurgeThreads_PostGlobalSweep(cx);
 
 #ifdef JS_THREADSAFE
@@ -3130,25 +3125,16 @@ GCCycle(JSContext *cx, JSCompartment *co
 }
 
 void
 js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Reason reason)
 {
     JSRuntime *rt = cx->runtime;
     JS_AbortIfWrongThread(rt);
 
-    /*
-     * Don't collect garbage if the runtime isn't up, and cx is not the last
-     * context in the runtime.  The last context must force a GC, and nothing
-     * should suppress that final collection or there may be shutdown leaks,
-     * or runtime bloat until the next context is created.
-     */
-    if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT)
-        return;
-
 #ifdef JS_GC_ZEAL
     struct AutoVerifyBarriers {
         JSContext *cx;
         bool inVerify;
         AutoVerifyBarriers(JSContext *cx) : cx(cx), inVerify(cx->runtime->gcVerifyData) {
             if (inVerify) EndVerifyBarriers(cx);
         }
         ~AutoVerifyBarriers() { if (inVerify) StartVerifyBarriers(cx); }
@@ -3162,17 +3148,17 @@ js_GC(JSContext *cx, JSCompartment *comp
     do {
         /*
          * Let the API user decide to defer a GC if it wants to (unless this
          * is the last context).  Invoke the callback regardless. Sample the
          * callback in case we are freely racing with a JS_SetGCCallback{,RT}
          * on another thread.
          */
         if (JSGCCallback callback = rt->gcCallback) {
-            if (!callback(cx, JSGC_BEGIN) && gckind != GC_LAST_CONTEXT)
+            if (!callback(cx, JSGC_BEGIN) && rt->hasContexts())
                 return;
         }
 
         {
             /* Lock out other GC allocator and collector invocations. */
             AutoLockGC lock(rt);
             rt->gcPoke = false;
             GCCycle(cx, comp, gckind);
@@ -3181,17 +3167,17 @@ js_GC(JSContext *cx, JSCompartment *comp
         /* We re-sample the callback again as the finalizers can change it. */
         if (JSGCCallback callback = rt->gcCallback)
             (void) callback(cx, JSGC_END);
 
         /*
          * On shutdown, iterate until finalizers or the JSGC_END callback
          * stop creating garbage.
          */
-    } while (gckind == GC_LAST_CONTEXT && rt->gcPoke);
+    } while (!rt->hasContexts() && rt->gcPoke);
 
     rt->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN;
 
     rt->gcChunkAllocationSinceLastGC = false;
 }
 
 namespace js {
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1403,24 +1403,18 @@ ShrinkGCBuffers(JSRuntime *rt);
 
 /*
  * Kinds of js_GC invocation.
  */
 typedef enum JSGCInvocationKind {
     /* Normal invocation. */
     GC_NORMAL           = 0,
 
-    /*
-     * Called from js_DestroyContext for last JSContext in a JSRuntime, when
-     * it is imperative that rt->gcPoke gets cleared early in js_GC.
-     */
-    GC_LAST_CONTEXT     = 1,
-
     /* Minimize GC triggers and release empty GC chunks right away. */
-    GC_SHRINK             = 2
+    GC_SHRINK             = 1
 } JSGCInvocationKind;
 
 /* Pass NULL for |comp| to get a full GC. */
 extern void
 js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, js::gcstats::Reason r);
 
 #ifdef JS_THREADSAFE
 /*
--- a/js/src/jslock.cpp
+++ b/js/src/jslock.cpp
@@ -735,35 +735,9 @@ js_Lock(JSContext *cx, JSThinLock *tl)
 }
 
 void
 js_Unlock(JSContext *cx, JSThinLock *tl)
 {
     ThinUnlock(tl, CX_THINLOCK_ID(cx));
 }
 
-void
-js_LockRuntime(JSRuntime *rt)
-{
-    PR_Lock(rt->rtLock);
-#ifdef DEBUG
-    rt->rtLockOwner = js_CurrentThreadId();
-#endif
-}
-
-void
-js_UnlockRuntime(JSRuntime *rt)
-{
-#ifdef DEBUG
-    rt->rtLockOwner = NULL;
-#endif
-    PR_Unlock(rt->rtLock);
-}
-
-#ifdef DEBUG
-JSBool
-js_IsRuntimeLocked(JSRuntime *rt)
-{
-    return js_CurrentThreadId() == rt->rtLockOwner;
-}
-#endif /* DEBUG */
-
 #endif /* JS_THREADSAFE */
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -108,40 +108,23 @@ typedef PRLock JSLock;
 #define JS_WAIT_CONDVAR(cv,to)      PR_WaitCondVar(cv,to)
 #define JS_NO_TIMEOUT               PR_INTERVAL_NO_TIMEOUT
 #define JS_NOTIFY_CONDVAR(cv)       PR_NotifyCondVar(cv)
 #define JS_NOTIFY_ALL_CONDVAR(cv)   PR_NotifyAllCondVar(cv)
 
 #define JS_LOCK(cx, tl)             js_Lock(cx, tl)
 #define JS_UNLOCK(cx, tl)           js_Unlock(cx, tl)
 
-#define JS_LOCK_RUNTIME(rt)         js_LockRuntime(rt)
-#define JS_UNLOCK_RUNTIME(rt)       js_UnlockRuntime(rt)
-
 extern void js_Lock(JSContext *cx, JSThinLock *tl);
 extern void js_Unlock(JSContext *cx, JSThinLock *tl);
-extern void js_LockRuntime(JSRuntime *rt);
-extern void js_UnlockRuntime(JSRuntime *rt);
 extern int js_SetupLocks(int,int);
 extern void js_CleanupLocks();
 extern void js_InitLock(JSThinLock *);
 extern void js_FinishLock(JSThinLock *);
 
-#ifdef DEBUG
-
-#define JS_IS_RUNTIME_LOCKED(rt)        js_IsRuntimeLocked(rt)
-
-extern JSBool js_IsRuntimeLocked(JSRuntime *rt);
-
-#else
-
-#define JS_IS_RUNTIME_LOCKED(rt)        0
-
-#endif /* DEBUG */
-
 #else  /* !JS_THREADSAFE */
 
 #define JS_ATOMIC_INCREMENT(p)      (++*(p))
 #define JS_ATOMIC_DECREMENT(p)      (--*(p))
 #define JS_ATOMIC_ADD(p,v)          (*(p) += (v))
 #define JS_ATOMIC_SET(p,v)          (*(p) = (v))
 
 #define js_CurrentThreadId()        ((void*)NULL)
@@ -153,21 +136,16 @@ extern JSBool js_IsRuntimeLocked(JSRunti
 #define JS_UNLOCK(cx, tl)           ((void)0)
 
 #define JS_NEW_CONDVAR(l)           NULL
 #define JS_DESTROY_CONDVAR(cv)      ((void)0)
 #define JS_WAIT_CONDVAR(cv,to)      ((void)0)
 #define JS_NOTIFY_CONDVAR(cv)       ((void)0)
 #define JS_NOTIFY_ALL_CONDVAR(cv)   ((void)0)
 
-#define JS_LOCK_RUNTIME(rt)         ((void)0)
-#define JS_UNLOCK_RUNTIME(rt)       ((void)0)
-
-#define JS_IS_RUNTIME_LOCKED(rt)        1
-
 #endif /* !JS_THREADSAFE */
 
 #define JS_LOCK_GC(rt)              JS_ACQUIRE_LOCK((rt)->gcLock)
 #define JS_UNLOCK_GC(rt)            JS_RELEASE_LOCK((rt)->gcLock)
 #define JS_AWAIT_GC_DONE(rt)        JS_WAIT_CONDVAR((rt)->gcDone, JS_NO_TIMEOUT)
 #define JS_NOTIFY_GC_DONE(rt)       JS_NOTIFY_ALL_CONDVAR((rt)->gcDone)
 #define JS_AWAIT_REQUEST_DONE(rt)   JS_WAIT_CONDVAR((rt)->requestDone,        \
                                                     JS_NO_TIMEOUT)