Bug 1052422 - Remove trivial shim functions that call into the GC r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 14 Aug 2014 10:32:06 +0100
changeset 199691 a24871f33bf90dfb7a4c88a4c7996bb1a799bca0
parent 199690 5b276b3d54dcac28639acf68a1bf0065289a38b5
child 199692 8f3ba188627a802a000d3824f15a395c8088f453
push id27315
push useremorley@mozilla.com
push dateFri, 15 Aug 2014 15:49:24 +0000
treeherdermozilla-central@48f814c8559f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1052422
milestone34.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 1052422 - Remove trivial shim functions that call into the GC r=sfink
js/public/GCAPI.h
js/src/builtin/TestingFunctions.cpp
js/src/devtools/rootAnalysis/loadCallgraph.js
js/src/gc/GCRuntime.h
js/src/gc/Iteration.cpp
js/src/gc/Verifier.cpp
js/src/gc/Zone.cpp
js/src/jit/BaselineDebugModeOSR.cpp
js/src/jsapi-tests/testGCFinalizeCallback.cpp
js/src/jsapi-tests/testGCHeapPostBarriers.cpp
js/src/jsapi-tests/testWeakMap.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsfriendapi.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/vm/ForkJoin.cpp
js/src/vm/Interpreter.cpp
js/src/vm/Runtime.cpp
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -85,17 +85,17 @@ namespace JS {
     D(SET_DOC_SHELL)                            \
     D(DOM_UTILS)                                \
     D(DOM_IPC)                                  \
     D(DOM_WORKER)                               \
     D(INTER_SLICE_GC)                           \
     D(REFRESH_FRAME)                            \
     D(FULL_GC_TIMER)                            \
     D(SHUTDOWN_CC)                              \
-    D(FINISH_LARGE_EVALUTE)
+    D(FINISH_LARGE_EVALUATE)
 
 namespace gcreason {
 
 /* GCReasons will end up looking like JSGC_MAYBEGC */
 enum Reason {
 #define MAKE_REASON(name) name,
     GCREASONS(MAKE_REASON)
 #undef MAKE_REASON
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -263,17 +263,17 @@ GC(JSContext *cx, unsigned argc, jsval *
 static bool
 MinorGC(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 #ifdef JSGC_GENERATIONAL
     if (args.get(0) == BooleanValue(true))
         cx->runtime()->gc.storeBuffer.setAboutToOverflow();
 
-    MinorGC(cx, gcreason::API);
+    cx->minorGC(gcreason::API);
 #endif
     args.rval().setUndefined();
     return true;
 }
 
 static const struct ParamPair {
     const char      *name;
     JSGCParamKey    param;
@@ -514,17 +514,17 @@ SelectForGC(JSContext *cx, unsigned argc
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /*
      * The selectedForMarking set is intended to be manually marked at slice
      * start to detect missing pre-barriers. It is invalid for nursery things
      * to be in the set, so evict the nursery before adding items.
      */
     JSRuntime *rt = cx->runtime();
-    MinorGC(rt, JS::gcreason::EVICT_NURSERY);
+    rt->gc.evictNursery();
 
     for (unsigned i = 0; i < args.length(); i++) {
         if (args[i].isObject()) {
             if (!rt->gc.selectForMarking(&args[i].toObject()))
                 return false;
         }
     }
 
@@ -623,17 +623,17 @@ GCSlice(JSContext *cx, unsigned argc, Va
     uint32_t budget = 0;
     if (args.length() == 1) {
         if (!ToUint32(cx, args[0], &budget))
             return false;
     } else {
         limit = false;
     }
 
-    GCDebugSlice(cx->runtime(), limit, budget);
+    cx->runtime()->gc.gcDebugSlice(limit, budget);
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 ValidateGC(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/devtools/rootAnalysis/loadCallgraph.js
+++ b/js/src/devtools/rootAnalysis/loadCallgraph.js
@@ -156,19 +156,20 @@ function loadCallgraph(file)
             delete gcFunctions[name];
     }
 
     for (var name in suppressedFieldCalls) {
         suppressedFunctions[name] = true;
     }
 
     for (var gcName of [ 'void js::gc::GCRuntime::collect(uint8, int64, uint32, uint32)',
-                         'void js::MinorGC(JSRuntime*, uint32)' ])
+                         'void js::gc::GCRuntime::minorGC(uint32)',
+                         'void js::gc::GCRuntime::minorGC(uint32)' ])
     {
-        assert(gcName in mangledName);
+        assert(gcName in mangledName, "GC function not found: " + gcName);
         addGCFunction(mangledName[gcName], "GC");
     }
 
     // Initialize the worklist to all known gcFunctions.
     var worklist = [];
     for (var name in gcFunctions)
         worklist.push(name);
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -273,20 +273,23 @@ class GCRuntime
     void decFJMinorCollecting() { fjCollectionCounter--; }
 
     bool triggerGC(JS::gcreason::Reason reason);
     bool triggerZoneGC(Zone *zone, JS::gcreason::Reason reason);
     bool maybeGC(Zone *zone);
     void maybePeriodicFullGC();
     void minorGC(JS::gcreason::Reason reason);
     void minorGC(JSContext *cx, JS::gcreason::Reason reason);
+    void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) { minorGC(reason); }
     void gcIfNeeded(JSContext *cx);
-    void collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
-                 JS::gcreason::Reason reason);
+    void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
     void gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
+    void gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
+    void gcDebugSlice(bool limit, int64_t objCount);
+
     void runDebugGC();
     inline void poke();
 
     void markRuntime(JSTracer *trc, bool useSavedRoots = false);
 
     void notifyDidPaint();
     void shrinkBuffers();
 
@@ -460,16 +463,18 @@ class GCRuntime
     void freeChunkList(Chunk *chunkListHead);
     void prepareToFreeChunk(ChunkInfo &info);
     void releaseChunk(Chunk *chunk);
 
     inline bool wantBackgroundAllocation() const;
 
     bool initZeal();
     void requestInterrupt(JS::gcreason::Reason reason);
+    void collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
+                 JS::gcreason::Reason reason);
     bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
                  JS::gcreason::Reason reason);
     gcstats::ZoneGCStats scanZonesBeforeGC();
     void budgetIncrementalGC(int64_t *budget);
     void resetIncrementalGC(const char *reason);
     void incrementalCollectSlice(int64_t budget, JS::gcreason::Reason reason,
                                  JSGCInvocationKind gckind);
     void pushZealSelectedObjects();
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -18,17 +18,17 @@ using namespace js;
 using namespace js::gc;
 
 void
 js::TraceRuntime(JSTracer *trc)
 {
     JS_ASSERT(!IS_GC_MARKING_TRACER(trc));
 
     JSRuntime *rt = trc->runtime();
-    MinorGC(rt, JS::gcreason::EVICT_NURSERY);
+    rt->gc.evictNursery();
     AutoPrepareForTracing prep(rt, WithAtoms);
     rt->gc.markRuntime(trc);
 }
 
 static void
 IterateCompartmentsArenasCells(JSRuntime *rt, Zone *zone, void *data,
                                JSIterateCompartmentCallback compartmentCallback,
                                IterateArenaCallback arenaCallback,
@@ -88,17 +88,17 @@ js::IterateChunks(JSRuntime *rt, void *d
     for (js::GCChunkSet::Range r = rt->gc.allChunks(); !r.empty(); r.popFront())
         chunkCallback(rt, data, r.front());
 }
 
 void
 js::IterateScripts(JSRuntime *rt, JSCompartment *compartment,
                    void *data, IterateScriptCallback scriptCallback)
 {
-    MinorGC(rt, JS::gcreason::EVICT_NURSERY);
+    rt->gc.evictNursery();
     AutoPrepareForTracing prep(rt, SkipAtoms);
 
     if (compartment) {
         for (ZoneCellIterUnderGC i(compartment->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
             JSScript *script = i.get<JSScript>();
             if (script->compartment() == compartment)
                 scriptCallback(rt, data, script);
         }
@@ -108,17 +108,17 @@ js::IterateScripts(JSRuntime *rt, JSComp
                 scriptCallback(rt, data, i.get<JSScript>());
         }
     }
 }
 
 void
 js::IterateGrayObjects(Zone *zone, GCThingCallback cellCallback, void *data)
 {
-    MinorGC(zone->runtimeFromMainThread(), JS::gcreason::EVICT_NURSERY);
+    zone->runtimeFromMainThread()->gc.evictNursery();
     AutoPrepareForTracing prep(zone->runtimeFromMainThread(), SkipAtoms);
 
     for (size_t finalizeKind = 0; finalizeKind <= FINALIZE_OBJECT_LAST; finalizeKind++) {
         for (ZoneCellIterUnderGC i(zone, AllocKind(finalizeKind)); !i.done(); i.next()) {
             JSObject *obj = i.get<JSObject>();
             if (obj->isMarked(GRAY))
                 cellCallback(data, obj);
         }
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -177,17 +177,17 @@ gc::GCRuntime::startVerifyPreBarriers()
      * The post barrier verifier requires the storebuffer to be enabled, but the
      * pre barrier verifier disables it as part of disabling GGC.  Don't allow
      * starting the pre barrier verifier if the post barrier verifier is already
      * running.
      */
     if (verifyPostData)
         return;
 
-    MinorGC(rt, JS::gcreason::EVICT_NURSERY);
+    evictNursery();
 
     AutoPrepareForTracing prep(rt, WithAtoms);
 
     if (!IsIncrementalGCSafe(rt))
         return;
 
     for (GCChunkSet::Range r(chunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
@@ -405,17 +405,17 @@ gc::GCRuntime::startVerifyPostBarriers()
 {
 #ifdef JSGC_GENERATIONAL
     if (verifyPostData ||
         incrementalState != NO_INCREMENTAL)
     {
         return;
     }
 
-    MinorGC(rt, JS::gcreason::EVICT_NURSERY);
+    evictNursery();
 
     number++;
 
     VerifyPostTracer *trc = js_new<VerifyPostTracer>(rt, JSTraceCallback(nullptr));
     if (!trc)
         return;
 
     verifyPostData = trc;
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -92,18 +92,20 @@ Zone::setGCMaxMallocBytes(size_t value)
      */
     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
     resetGCMallocBytes();
 }
 
 void
 Zone::onTooMuchMalloc()
 {
-    if (!gcMallocGCTriggered)
-        gcMallocGCTriggered = TriggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC);
+    if (!gcMallocGCTriggered) {
+        GCRuntime &gc = runtimeFromAnyThread()->gc;
+        gcMallocGCTriggered = gc.triggerZoneGC(this, JS::gcreason::TOO_MUCH_MALLOC);
+    }
 }
 
 void
 Zone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
 {
     /*
      * Periodically release observed types for all scripts. This is safe to
      * do when there are no frames for the zone on the stack.
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -653,17 +653,17 @@ jit::RecompileOnStackBaselineScriptsForD
             if (!CollectOnStackScripts(cx, iter, entries))
                 return false;
         }
     }
 
 #ifdef JSGC_GENERATIONAL
     // Scripts can entrain nursery things. See note in js::ReleaseAllJITCode.
     if (!entries.empty())
-        MinorGC(cx->runtime(), JS::gcreason::EVICT_NURSERY);
+        cx->runtime()->gc.evictNursery();
 #endif
 
     // When the profiler is enabled, we need to suppress sampling from here until
     // the end of the function, since the basline jit scripts are in a state of
     // flux.
     AutoSuppressProfilerSampling suppressProfilerSampling(cx);
 
     // Try to recompile all the scripts. If we encounter an error, we need to
--- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp
+++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp
@@ -83,22 +83,22 @@ BEGIN_TEST(testGCFinalizeCallback)
 
 #ifdef JS_GC_ZEAL
 
     /* Full GC with reset due to new compartment, becoming compartment GC. */
 
     FinalizeCalls = 0;
     JS_SetGCZeal(cx, 9, 1000000);
     JS::PrepareForFullGC(rt);
-    js::GCDebugSlice(rt, true, 1);
+    rt->gc.gcDebugSlice(true, 1);
     CHECK(rt->gc.state() == js::gc::MARK);
     CHECK(rt->gc.isFullGc());
 
     JS::RootedObject global4(cx, createGlobal());
-    js::GCDebugSlice(rt, true, 1);
+    rt->gc.gcDebugSlice(true, 1);
     CHECK(rt->gc.state() == js::gc::NO_INCREMENTAL);
     CHECK(!rt->gc.isFullGc());
     CHECK(checkMultipleGroups());
     CHECK(checkFinalizeStatus());
 
     for (unsigned i = 0; i < FinalizeCalls - 1; ++i)
         CHECK(!IsCompartmentGCBuffer[i]);
     CHECK(IsCompartmentGCBuffer[FinalizeCalls - 1]);
--- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
+++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
@@ -46,17 +46,17 @@ TestHeapPostBarriers(T initialObj)
     CHECK(heapData);
     CHECK(Passthrough(heapData->get() == nullptr));
     heapData->set(initialObj);
 
     /* Store the pointer as an integer so that the hazard analysis will miss it. */
     uintptr_t initialObjAsInt = uintptr_t(initialObj);
 
     /* Perform minor GC and check heap wrapper is udated with new pointer. */
-    js::MinorGC(cx, JS::gcreason::API);
+    cx->minorGC(JS::gcreason::API);
     CHECK(uintptr_t(heapData->get()) != initialObjAsInt);
     CHECK(!js::gc::IsInsideNursery(heapData->get()));
 
     /* Check object is definitely still alive. */
     JS::Rooted<T> obj(cx, heapData->get());
     JS::RootedValue value(cx);
     CHECK(JS_GetProperty(cx, obj, "x", &value));
     CHECK(value.isInt32());
--- a/js/src/jsapi-tests/testWeakMap.cpp
+++ b/js/src/jsapi-tests/testWeakMap.cpp
@@ -82,30 +82,30 @@ BEGIN_TEST(testWeakMap_keyDelegates)
 
     SetKeyDelegate(key, delegate);
 
     /*
      * Perform an incremental GC, introducing an unmarked CCW to force the map
      * zone to finish marking before the delegate zone.
      */
     CHECK(newCCW(map, delegate));
-    GCDebugSlice(rt, true, 1000000);
+    rt->gc.gcDebugSlice(true, 1000000);
 #ifdef DEBUG
     CHECK(map->zone()->lastZoneGroupIndex() < delegate->zone()->lastZoneGroupIndex());
 #endif
 
     /* Add our entry to the weakmap. */
     JS::RootedValue val(cx, JS::Int32Value(1));
     CHECK(SetWeakMapEntry(cx, map, key, val));
     CHECK(checkSize(map, 1));
 
     /* Check the delegate keeps the entry alive even if the key is not reachable. */
     key = nullptr;
     CHECK(newCCW(map, delegate));
-    GCDebugSlice(rt, true, 100000);
+    rt->gc.gcDebugSlice(true, 100000);
     CHECK(checkSize(map, 1));
 
     /*
      * Check that the zones finished marking at the same time, which is
      * neccessary because of the presence of the delegate and the CCW.
      */
 #ifdef DEBUG
     CHECK(map->zone()->lastZoneGroupIndex() == delegate->zone()->lastZoneGroupIndex());
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1868,17 +1868,17 @@ JS_IsMarkingGray(JSTracer *trc)
 }
 #endif
 
 JS_PUBLIC_API(void)
 JS_GC(JSRuntime *rt)
 {
     AssertHeapIsIdle(rt);
     JS::PrepareForFullGC(rt);
-    GC(rt, GC_NORMAL, JS::gcreason::API);
+    rt->gc.gc(GC_NORMAL, JS::gcreason::API);
 }
 
 JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext *cx)
 {
     GCRuntime &gc = cx->runtime()->gc;
     if (!gc.maybeGC(cx->zone()))
         gc.maybePeriodicFullGC();
@@ -4802,17 +4802,17 @@ Evaluate(JSContext *cx, HandleObject obj
     // After evaluation, the compiled script will not be run again.
     // script->ensureRanAnalysis allocated 1 analyze::Bytecode for every opcode
     // which for large scripts means significant memory. Perform a GC eagerly
     // to clear out this analysis data before anything happens to inhibit the
     // flushing of this memory (such as setting requestAnimationFrame).
     if (script->length() > LARGE_SCRIPT_LENGTH) {
         script = nullptr;
         PrepareZoneForGC(cx->zone());
-        GC(cx->runtime(), GC_NORMAL, JS::gcreason::FINISH_LARGE_EVALUTE);
+        cx->runtime()->gc.gc(GC_NORMAL, JS::gcreason::FINISH_LARGE_EVALUATE);
     }
 
     return result;
 }
 
 static bool
 Evaluate(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optionsArg,
          const jschar *chars, size_t length, JS::Value *rval)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -246,17 +246,17 @@ js::DestroyContext(JSContext *cx, Destro
          * This printing depends on atoms still existing.
          */
         for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
             c->types.print(cx, false);
     }
     if (mode == DCM_FORCE_GC) {
         JS_ASSERT(!rt->isHeapBusy());
         JS::PrepareForFullGC(rt);
-        GC(rt, GC_NORMAL, JS::gcreason::DESTROY_CONTEXT);
+        rt->gc.gc(GC_NORMAL, JS::gcreason::DESTROY_CONTEXT);
     }
     js_delete_poison(cx);
 }
 
 void
 ContextFriendFields::checkNoGCRooters() {
 #if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
     for (int i = 0; i < THING_ROOT_LIMIT; ++i)
@@ -981,17 +981,17 @@ js::InvokeInterruptCallback(JSContext *c
     // thread is racing us here we will accumulate another callback request
     // which will be serviced at the next opportunity.
     rt->interrupt = false;
 
     // IonMonkey sets its stack limit to UINTPTR_MAX to trigger interrupt
     // callbacks.
     rt->resetJitStackLimit();
 
-    js::gc::GCIfNeeded(cx);
+    cx->gcIfNeeded();
 
     rt->interruptPar = false;
 
     // A worker thread may have requested an interrupt after finishing an Ion
     // compilation.
     jit::AttachFinishedCompilations(cx);
 
     // Important: Additional callbacks can occur inside the callback handler
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -543,16 +543,24 @@ struct JSContext : public js::ExclusiveC
 
     // The generational GC nursery may only be used on the main thread.
 #ifdef JSGC_GENERATIONAL
     inline js::Nursery &nursery() {
         return runtime_->gc.nursery;
     }
 #endif
 
+    void minorGC(JS::gcreason::Reason reason) {
+        runtime_->gc.minorGC(this, reason);
+    }
+
+    void gcIfNeeded() {
+        runtime_->gc.gcIfNeeded(this);
+    }
+
   private:
     /* Innermost-executing generator or null if no generator are executing. */
     JSGenerator *innermostGenerator_;
   public:
     JSGenerator *innermostGenerator() const { return innermostGenerator_; }
     void enterGenerator(JSGenerator *gen);
     void leaveGenerator(JSGenerator *gen);
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -192,35 +192,35 @@ JS_FRIEND_API(void)
 JS::SkipZoneForGC(Zone *zone)
 {
     zone->unscheduleGC();
 }
 
 JS_FRIEND_API(void)
 JS::GCForReason(JSRuntime *rt, gcreason::Reason reason)
 {
-    GC(rt, GC_NORMAL, reason);
+    rt->gc.gc(GC_NORMAL, reason);
 }
 
 JS_FRIEND_API(void)
 JS::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason)
 {
-    GC(rt, GC_SHRINK, reason);
+    rt->gc.gc(GC_SHRINK, reason);
 }
 
 JS_FRIEND_API(void)
 JS::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis)
 {
-    GCSlice(rt, GC_NORMAL, reason, millis);
+    rt->gc.gcSlice(GC_NORMAL, reason, millis);
 }
 
 JS_FRIEND_API(void)
 JS::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason)
 {
-    GCFinalSlice(rt, GC_NORMAL, reason);
+    rt->gc.gcFinalSlice(GC_NORMAL, reason);
 }
 
 JS_FRIEND_API(JSPrincipals *)
 JS_GetCompartmentPrincipals(JSCompartment *compartment)
 {
     return compartment->principals;
 }
 
@@ -805,17 +805,17 @@ DumpHeapVisitRoot(JSTracer *trc, void **
             dtrc->getTracingEdgeName(buffer, sizeof(buffer)));
 }
 
 void
 js::DumpHeapComplete(JSRuntime *rt, FILE *fp, js::DumpHeapNurseryBehaviour nurseryBehaviour)
 {
 #ifdef JSGC_GENERATIONAL
     if (nurseryBehaviour == js::CollectNurseryBeforeDump)
-        MinorGC(rt, JS::gcreason::API);
+        rt->gc.evictNursery(JS::gcreason::API);
 #endif
 
     DumpHeapTracer dtrc(fp, rt, DumpHeapVisitRoot, TraceWeakMapKeysValues);
     TraceRuntime(&dtrc);
 
     fprintf(dtrc.output, "==========\n");
 
     dtrc.setTraceCallback(DumpHeapVisitChild);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -934,17 +934,17 @@ Chunk::allocateArena(Zone *zone, AllocKi
     aheader->init(zone, thingKind);
     if (MOZ_UNLIKELY(!hasAvailableArenas()))
         removeFromAvailableList();
 
     zone->usage.addGCArena();
 
     if (zone->usage.gcBytes() >= zone->threshold.gcTriggerBytes()) {
         AutoUnlockGC unlock(rt);
-        TriggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
+        rt->gc.triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
     }
 
     return aheader;
 }
 
 inline void
 GCRuntime::updateOnArenaFree(const ChunkInfo &info)
 {
@@ -1181,17 +1181,17 @@ GCRuntime::setZeal(uint8_t zeal, uint32_
 {
     if (verifyPreData)
         VerifyBarriers(rt, PreBarrierVerifier);
     if (verifyPostData)
         VerifyBarriers(rt, PostBarrierVerifier);
 
 #ifdef JSGC_GENERATIONAL
     if (zealMode == ZealGenerationalGCValue) {
-        minorGC(JS::gcreason::DEBUG_GC);
+        evictNursery(JS::gcreason::DEBUG_GC);
         nursery.leaveZealMode();
     }
 
     if (zeal == ZealGenerationalGCValue)
         nursery.enterZealMode();
 #endif
 
     bool schedule = zeal >= js::gc::ZealAllocValue;
@@ -2164,17 +2164,17 @@ RunLastDitchGC(JSContext *cx, JS::Zone *
     JS_ASSERT(!InParallelSection());
 
     PrepareZoneForGC(zone);
 
     JSRuntime *rt = cx->runtime();
 
     /* The last ditch GC preserves all atoms. */
     AutoKeepAtoms keepAtoms(cx->perThreadData);
-    GC(rt, GC_NORMAL, JS::gcreason::LAST_DITCH);
+    rt->gc.gc(GC_NORMAL, JS::gcreason::LAST_DITCH);
 
     /*
      * The JSGC_END callback can legitimately allocate new GC
      * things and populate the free list. If that happens, just
      * return that list head.
      */
     size_t thingSize = Arena::thingSize(thingKind);
     if (void *thing = zone->allocator.arenas.allocateFromFreeList(thingKind, thingSize))
@@ -2266,22 +2266,16 @@ ArenaLists::refillFreeList(ThreadSafeCon
 }
 
 template void *
 ArenaLists::refillFreeList<NoGC>(ThreadSafeContext *cx, AllocKind thingKind);
 
 template void *
 ArenaLists::refillFreeList<CanGC>(ThreadSafeContext *cx, AllocKind thingKind);
 
-JSGCTraceKind
-js_GetGCThingTraceKind(void *thing)
-{
-    return GetGCThingTraceKind(thing);
-}
-
 /* static */ int64_t
 SliceBudget::TimeBudget(int64_t millis)
 {
     return millis * PRMJ_USEC_PER_MSEC;
 }
 
 /* static */ int64_t
 SliceBudget::WorkBudget(int64_t work)
@@ -2330,22 +2324,16 @@ GCRuntime::requestInterrupt(JS::gcreason
         return;
 
     isNeeded = true;
     triggerReason = reason;
     rt->requestInterrupt(JSRuntime::RequestInterruptMainThread);
 }
 
 bool
-js::TriggerGC(JSRuntime *rt, JS::gcreason::Reason reason)
-{
-    return rt->gc.triggerGC(reason);
-}
-
-bool
 GCRuntime::triggerGC(JS::gcreason::Reason reason)
 {
     /* Wait till end of parallel section to trigger GC. */
     if (InParallelSection()) {
         ForkJoinContext::current()->requestGC(reason);
         return true;
     }
 
@@ -2365,22 +2353,16 @@ GCRuntime::triggerGC(JS::gcreason::Reaso
         return false;
 
     JS::PrepareForFullGC(rt);
     requestInterrupt(reason);
     return true;
 }
 
 bool
-js::TriggerZoneGC(Zone *zone, JS::gcreason::Reason reason)
-{
-    return zone->runtimeFromAnyThread()->gc.triggerZoneGC(zone, reason);
-}
-
-bool
 GCRuntime::triggerZoneGC(Zone *zone, JS::gcreason::Reason reason)
 {
     /*
      * If parallel threads are running, wait till they
      * are stopped to trigger GC.
      */
     if (InParallelSection()) {
         ForkJoinContext::current()->requestZoneGC(zone, reason);
@@ -2396,58 +2378,58 @@ GCRuntime::triggerZoneGC(Zone *zone, JS:
         return false;
 
     /* GC is already running. */
     if (rt->isHeapCollecting())
         return false;
 
 #ifdef JS_GC_ZEAL
     if (zealMode == ZealAllocValue) {
-        TriggerGC(rt, reason);
+        triggerGC(reason);
         return true;
     }
 #endif
 
     if (rt->isAtomsZone(zone)) {
         /* We can't do a zone GC of the atoms compartment. */
-        TriggerGC(rt, reason);
+        triggerGC(reason);
         return true;
     }
 
     PrepareZoneForGC(zone);
     requestInterrupt(reason);
     return true;
 }
 
 bool
 GCRuntime::maybeGC(Zone *zone)
 {
     JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
 #ifdef JS_GC_ZEAL
     if (zealMode == ZealAllocValue || zealMode == ZealPokeValue) {
         JS::PrepareForFullGC(rt);
-        GC(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
+        gc(GC_NORMAL, JS::gcreason::MAYBEGC);
         return true;
     }
 #endif
 
     if (isNeeded) {
-        GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
+        gcSlice(GC_NORMAL, JS::gcreason::MAYBEGC);
         return true;
     }
 
     double factor = schedulingState.inHighFrequencyGCMode() ? 0.85 : 0.9;
     if (zone->usage.gcBytes() > 1024 * 1024 &&
         zone->usage.gcBytes() >= factor * zone->threshold.gcTriggerBytes() &&
         incrementalState == NO_INCREMENTAL &&
         !isBackgroundSweeping())
     {
         PrepareZoneForGC(zone);
-        GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
+        gcSlice(GC_NORMAL, JS::gcreason::MAYBEGC);
         return true;
     }
 
     return false;
 }
 
 void
 GCRuntime::maybePeriodicFullGC()
@@ -2463,17 +2445,17 @@ GCRuntime::maybePeriodicFullGC()
      */
 #ifndef JS_MORE_DETERMINISTIC
     int64_t now = PRMJ_Now();
     if (nextFullGCTime && nextFullGCTime <= now) {
         if (chunkAllocationSinceLastGC ||
             numArenasFreeCommitted > decommitThreshold)
         {
             JS::PrepareForFullGC(rt);
-            GCSlice(rt, GC_SHRINK, JS::gcreason::MAYBEGC);
+            gcSlice(GC_SHRINK, JS::gcreason::MAYBEGC);
         } else {
             nextFullGCTime = now + GC_IDLE_FULL_SPAN;
         }
     }
 #endif
 }
 
 void
@@ -4762,17 +4744,17 @@ GCRuntime::incrementalCollectSlice(int64
 
     gc::State initialState = incrementalState;
 
     int zeal = 0;
 #ifdef JS_GC_ZEAL
     if (reason == JS::gcreason::DEBUG_GC && budget != SliceBudget::Unlimited) {
         /*
          * Do the incremental collection type specified by zeal mode if the
-         * collection was triggered by RunDebugGC() and incremental GC has not
+         * collection was triggered by runDebugGC() and incremental GC has not
          * been cancelled by resetIncrementalGC().
          */
         zeal = zealMode;
     }
 #endif
 
     JS_ASSERT_IF(incrementalState != NO_INCREMENTAL, isIncremental);
     isIncremental = budget != SliceBudget::Unlimited;
@@ -5195,25 +5177,19 @@ GCRuntime::collect(bool incremental, int
         repeat = (poked && cleanUpEverything) || wasReset || repeatForDeadZone;
     } while (repeat);
 
     if (incrementalState == NO_INCREMENTAL)
         EnqueuePendingParseTasksAfterGC(rt);
 }
 
 void
-js::GC(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason)
-{
-    rt->gc.collect(false, SliceBudget::Unlimited, gckind, reason);
-}
-
-void
-js::GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis)
-{
-    rt->gc.gcSlice(gckind, reason, millis);
+GCRuntime::gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason)
+{
+    collect(false, SliceBudget::Unlimited, gckind, reason);
 }
 
 void
 GCRuntime::gcSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis)
 {
     int64_t budget;
     if (millis)
         budget = SliceBudget::TimeBudget(millis);
@@ -5221,19 +5197,19 @@ GCRuntime::gcSlice(JSGCInvocationKind gc
         budget = sliceBudget * IGC_MARK_SLICE_MULTIPLIER;
     else
         budget = sliceBudget;
 
     collect(true, budget, gckind, reason);
 }
 
 void
-js::GCFinalSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason)
-{
-    rt->gc.collect(true, SliceBudget::Unlimited, gckind, reason);
+GCRuntime::gcFinalSlice(JSGCInvocationKind gckind, JS::gcreason::Reason reason)
+{
+    collect(true, SliceBudget::Unlimited, gckind, reason);
 }
 
 void
 GCRuntime::notifyDidPaint()
 {
 #ifdef JS_GC_ZEAL
     if (zealMode == ZealFrameVerifierPreValue) {
         verifyPreBarriers();
@@ -5266,26 +5242,26 @@ ZonesSelected(JSRuntime *rt)
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         if (zone->isGCScheduled())
             return true;
     }
     return false;
 }
 
 void
-js::GCDebugSlice(JSRuntime *rt, bool limit, int64_t objCount)
+GCRuntime::gcDebugSlice(bool limit, int64_t objCount)
 {
     int64_t budget = limit ? SliceBudget::WorkBudget(objCount) : SliceBudget::Unlimited;
     if (!ZonesSelected(rt)) {
         if (JS::IsIncrementalGCInProgress(rt))
             JS::PrepareForIncrementalGC(rt);
         else
             JS::PrepareForFullGC(rt);
     }
-    rt->gc.collect(true, budget, GC_NORMAL, JS::gcreason::DEBUG_GC);
+    collect(true, budget, GC_NORMAL, JS::gcreason::DEBUG_GC);
 }
 
 /* Schedule a full GC unless a zone will already be collected. */
 void
 js::PrepareForDebugGC(JSRuntime *rt)
 {
     if (!ZonesSelected(rt))
         JS::PrepareForFullGC(rt);
@@ -5306,43 +5282,31 @@ GCRuntime::shrinkBuffers()
 
     if (CanUseExtraThreads())
         helperState.startBackgroundShrink();
     else
         expireChunksAndArenas(true);
 }
 
 void
-js::MinorGC(JSRuntime *rt, JS::gcreason::Reason reason)
-{
-    rt->gc.minorGC(reason);
-}
-
-void
 GCRuntime::minorGC(JS::gcreason::Reason reason)
 {
 #ifdef JSGC_GENERATIONAL
     TraceLogger *logger = TraceLoggerForMainThread(rt);
     AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
     nursery.collect(rt, reason, nullptr);
     JS_ASSERT_IF(!rt->mainThread.suppressGC, nursery.isEmpty());
 #endif
 }
 
 void
-js::MinorGC(JSContext *cx, JS::gcreason::Reason reason)
+GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
 {
     // Alternate to the runtime-taking form above which allows marking type
     // objects as needing pretenuring.
-    cx->runtime()->gc.minorGC(cx, reason);
-}
-
-void
-GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
-{
 #ifdef JSGC_GENERATIONAL
     TraceLogger *logger = TraceLoggerForMainThread(rt);
     AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
     Nursery::TypeObjectList pretenureTypes;
     nursery.collect(rt, reason, &pretenureTypes);
     for (size_t i = 0; i < pretenureTypes.length(); i++) {
         if (pretenureTypes[i]->canPreTenure())
             pretenureTypes[i]->setShouldPreTenure(cx);
@@ -5373,51 +5337,39 @@ GCRuntime::enableGenerationalGC()
     if (generationalDisabled == 0) {
         nursery.enable();
         storeBuffer.enable();
     }
 #endif
 }
 
 void
-js::gc::GCIfNeeded(JSContext *cx)
-{
-    cx->runtime()->gc.gcIfNeeded(cx);
-}
-
-void
 GCRuntime::gcIfNeeded(JSContext *cx)
 {
 #ifdef JSGC_GENERATIONAL
     /*
      * In case of store buffer overflow perform minor GC first so that the
      * correct reason is seen in the logs.
      */
     if (storeBuffer.isAboutToOverflow())
         minorGC(cx, JS::gcreason::FULL_STORE_BUFFER);
 #endif
 
     if (isNeeded)
         gcSlice(GC_NORMAL, rt->gc.triggerReason, 0);
 }
 
-void
-js::gc::FinishBackgroundFinalize(JSRuntime *rt)
-{
-    rt->gc.waitBackgroundSweepEnd();
-}
-
 AutoFinishGC::AutoFinishGC(JSRuntime *rt)
 {
     if (JS::IsIncrementalGCInProgress(rt)) {
         JS::PrepareForIncrementalGC(rt);
         JS::FinishIncrementalGC(rt, JS::gcreason::API);
     }
 
-    gc::FinishBackgroundFinalize(rt);
+    rt->gc.waitBackgroundSweepEnd();
 }
 
 AutoPrepareForTracing::AutoPrepareForTracing(JSRuntime *rt, ZoneSelector selector)
   : finish(rt),
     session(rt),
     copy(rt, selector)
 {
     rt->gc.recordNativeStackTop();
@@ -5516,32 +5468,26 @@ gc::MergeCompartments(JSCompartment *sou
     target->zone()->allocator.arenas.adoptArenas(rt, &source->zone()->allocator.arenas);
     target->zone()->usage.adopt(source->zone()->usage);
 
     // Merge other info in source's zone into target's zone.
     target->zone()->types.typeLifoAlloc.transferFrom(&source->zone()->types.typeLifoAlloc);
 }
 
 void
-gc::RunDebugGC(JSContext *cx)
-{
-    cx->runtime()->gc.runDebugGC();
-}
-
-void
 GCRuntime::runDebugGC()
 {
 #ifdef JS_GC_ZEAL
     int type = zealMode;
 
     if (rt->mainThread.suppressGC)
         return;
 
     if (type == js::gc::ZealGenerationalGCValue)
-        return MinorGC(rt, JS::gcreason::DEBUG_GC);
+        return minorGC(JS::gcreason::DEBUG_GC);
 
     PrepareForDebugGC(rt);
 
     if (type == ZealIncrementalRootsThenFinish ||
         type == ZealIncrementalMarkAllThenFinish ||
         type == ZealIncrementalMultipleSlices)
     {
         js::gc::State initialState = incrementalState;
@@ -5629,17 +5575,17 @@ void PreventGCDuringInteractiveDebug()
 void
 js::ReleaseAllJITCode(FreeOp *fop)
 {
 #ifdef JSGC_GENERATIONAL
     /*
      * Scripts can entrain nursery things, inserting references to the script
      * into the store buffer. Clear the store buffer before discarding scripts.
      */
-    MinorGC(fop->runtime(), JS::gcreason::EVICT_NURSERY);
+    fop->runtime()->gc.evictNursery();
 #endif
 
     for (ZonesIter zone(fop->runtime(), SkipAtoms); !zone.done(); zone.next()) {
         if (!zone->jitZone())
             continue;
 
 #ifdef DEBUG
         /* Assert no baseline scripts are marked as active. */
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -958,59 +958,33 @@ namespace js {
 class InterpreterFrame;
 
 extern void
 MarkCompartmentActive(js::InterpreterFrame *fp);
 
 extern void
 TraceRuntime(JSTracer *trc);
 
-/* Must be called with GC lock taken. */
-extern bool
-TriggerGC(JSRuntime *rt, JS::gcreason::Reason reason);
-
-/* Must be called with GC lock taken. */
-extern bool
-TriggerZoneGC(Zone *zone, JS::gcreason::Reason reason);
-
 extern void
 ReleaseAllJITCode(FreeOp *op);
 
 /*
  * Kinds of js_GC invocation.
  */
 typedef enum JSGCInvocationKind {
     /* Normal invocation. */
     GC_NORMAL           = 0,
 
     /* Minimize GC triggers and release empty GC chunks right away. */
     GC_SHRINK             = 1
 } JSGCInvocationKind;
 
 extern void
-GC(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason);
-
-extern void
-GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
-
-extern void
-GCFinalSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reason);
-
-extern void
-GCDebugSlice(JSRuntime *rt, bool limit, int64_t objCount);
-
-extern void
 PrepareForDebugGC(JSRuntime *rt);
 
-extern void
-MinorGC(JSRuntime *rt, JS::gcreason::Reason reason);
-
-extern void
-MinorGC(JSContext *cx, JS::gcreason::Reason reason);
-
 /* Functions for managing cross compartment gray pointers. */
 
 extern void
 DelayCrossCompartmentGrayMarking(JSObject *src);
 
 extern void
 NotifyGCNukeWrapper(JSObject *o);
 
@@ -1220,27 +1194,16 @@ js_FinalizeStringRT(JSRuntime *rt, JSStr
 namespace js {
 
 JSCompartment *
 NewCompartment(JSContext *cx, JS::Zone *zone, JSPrincipals *principals,
                const JS::CompartmentOptions &options);
 
 namespace gc {
 
-extern void
-GCIfNeeded(JSContext *cx);
-
-/* Tries to run a GC no matter what (used for GC zeal). */
-void
-RunDebugGC(JSContext *cx);
-
-/* Wait for the background thread to finish sweeping if it is running. */
-void
-FinishBackgroundFinalize(JSRuntime *rt);
-
 /*
  * Merge all contents of source into target. This can only be used if source is
  * the only compartment in its zone.
  */
 void
 MergeCompartments(JSCompartment *source, JSCompartment *target);
 
 const int ZealPokeValue = 1;
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -363,24 +363,23 @@ class ZoneCellIter : public ZoneCellIter
          * We have a single-threaded runtime, so there's no need to protect
          * against other threads iterating or allocating. However, we do have
          * background finalization; we have to wait for this to finish if it's
          * currently active.
          */
         if (IsBackgroundFinalized(kind) &&
             zone->allocator.arenas.needBackgroundFinalizeWait(kind))
         {
-            gc::FinishBackgroundFinalize(zone->runtimeFromMainThread());
+            zone->runtimeFromMainThread()->gc.waitBackgroundSweepEnd();
         }
 
 #ifdef JSGC_GENERATIONAL
         /* Evict the nursery before iterating so we can see all things. */
         JSRuntime *rt = zone->runtimeFromMainThread();
-        if (!rt->gc.nursery.isEmpty())
-            MinorGC(rt, JS::gcreason::EVICT_NURSERY);
+        rt->gc.evictNursery();
 #endif
 
         if (lists->isSynchronizedFreeList(kind)) {
             lists = nullptr;
         } else {
             JS_ASSERT(!zone->runtimeFromMainThread()->isHeapBusy());
             lists->copyFreeListToArena(kind);
         }
@@ -468,17 +467,17 @@ TryNewNurseryObject(JSContext *cx, size_
 {
     JS_ASSERT(!IsAtomsCompartment(cx->compartment()));
     JSRuntime *rt = cx->runtime();
     Nursery &nursery = rt->gc.nursery;
     JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots);
     if (obj)
         return obj;
     if (allowGC && !rt->mainThread.suppressGC) {
-        MinorGC(cx, JS::gcreason::OUT_OF_NURSERY);
+        cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
 
         /* Exceeding gcMaxBytes while tenuring can disable the Nursery. */
         if (nursery.isEnabled()) {
             JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots);
             JS_ASSERT(obj);
             return obj;
         }
     }
@@ -542,23 +541,23 @@ CheckAllocatorState(ThreadSafeContext *c
     if (!PossiblyFail()) {
         js_ReportOutOfMemory(cx);
         return false;
     }
 
     if (allowGC) {
 #ifdef JS_GC_ZEAL
         if (rt->gc.needZealousGC())
-            js::gc::RunDebugGC(ncx);
+            rt->gc.runDebugGC();
 #endif
 
         if (rt->interrupt) {
             // Invoking the interrupt callback can fail and we can't usefully
             // handle that here. Just check in case we need to collect instead.
-            js::gc::GCIfNeeded(ncx);
+            ncx->gcIfNeeded();
         }
     }
 
     return true;
 }
 
 template <typename T>
 static inline void
@@ -677,17 +676,17 @@ AllocateObjectForCacheHit(JSContext *cx,
         size_t thingSize = Arena::thingSize(kind);
 
         JS_ASSERT(thingSize == Arena::thingSize(kind));
         if (!CheckAllocatorState<NoGC>(cx, kind))
             return nullptr;
 
         JSObject *obj = TryNewNurseryObject<NoGC>(cx, thingSize, 0);
         if (!obj && allowGC) {
-            MinorGC(cx, JS::gcreason::OUT_OF_NURSERY);
+            cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
             return nullptr;
         }
         return obj;
     }
 #endif
 
     JSObject *obj = AllocateObject<NoGC>(cx, kind, 0, heap);
     if (!obj && allowGC) {
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -350,17 +350,17 @@ ForkJoinActivation::ForkJoinActivation(J
     // a minor GC to ensure no cross-generation pointers get
     // created:
 
     if (JS::IsIncrementalGCInProgress(cx->runtime())) {
         JS::PrepareForIncrementalGC(cx->runtime());
         JS::FinishIncrementalGC(cx->runtime(), JS::gcreason::API);
     }
 
-    MinorGC(cx->runtime(), JS::gcreason::API);
+    cx->runtime()->gc.evictNursery();
 
     cx->runtime()->gc.waitBackgroundSweepEnd();
 
     JS_ASSERT(!cx->runtime()->needsIncrementalBarrier());
     JS_ASSERT(!cx->zone()->needsIncrementalBarrier());
 }
 
 ForkJoinActivation::~ForkJoinActivation()
@@ -1487,20 +1487,21 @@ void
 ForkJoinShared::transferArenasToCompartmentAndProcessGCRequests()
 {
     JSCompartment *comp = cx_->compartment();
     for (unsigned i = 0; i < threadPool_->numWorkers(); i++)
         comp->adoptWorkerAllocator(allocators_[i]);
 
     if (gcRequested_) {
         Spew(SpewGC, "Triggering garbage collection in SpiderMonkey heap");
+        gc::GCRuntime &gc = cx_->runtime()->gc;
         if (!gcZone_)
-            TriggerGC(cx_->runtime(), gcReason_);
+            gc.triggerGC(gcReason_);
         else
-            TriggerZoneGC(gcZone_, gcReason_);
+            gc.triggerZoneGC(gcZone_, gcReason_);
         gcRequested_ = false;
         gcZone_ = nullptr;
     }
 }
 
 bool
 ForkJoinShared::executeFromWorker(ThreadPoolWorker *worker, uintptr_t stackLimit)
 {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -410,17 +410,17 @@ js::RunScript(JSContext *cx, RunState &s
 
     return Interpret(cx, state);
 }
 
 struct AutoGCIfNeeded
 {
     JSContext *cx_;
     explicit AutoGCIfNeeded(JSContext *cx) : cx_(cx) {}
-    ~AutoGCIfNeeded() { js::gc::GCIfNeeded(cx_); }
+    ~AutoGCIfNeeded() { cx_->gcIfNeeded(); }
 };
 
 /*
  * Find a function reference and its 'this' value implicit first parameter
  * under argc arguments on cx's stack, and call the function.  Push missing
  * required arguments, allocate declared local variables, and pop everything
  * when done.  Then push the return value.
  */
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -371,17 +371,17 @@ JSRuntime::~JSRuntime()
          * interned atoms and Ion trampolines.
          */
         beingDestroyed_ = true;
 
         /* Allow the GC to release scripts that were being profiled. */
         profilingScripts = false;
 
         JS::PrepareForFullGC(this);
-        GC(this, GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
+        gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
     }
 
     /*
      * Clear the self-hosted global and delete self-hosted classes *after*
      * GC, as finalizers for objects check for clasp->finalize during GC.
      */
     finishSelfHosting();