diff --git a/js/src/Makefile.in b/js/src/Makefile.in
index b0e6e7efd5461caf6790b0b2875228d58b205777..e9c10d1e4598b7b33e9511ce89afd8ae2c9fb594 100644
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -148,7 +148,6 @@ CPPSRCS		= \
 		Memory.cpp \
 		Statistics.cpp \
 		StoreBuffer.cpp \
-		FindSCCs.cpp \
 		Iteration.cpp \
 		Verifier.cpp \
 		StringBuffer.cpp \
diff --git a/js/src/gc/FindSCCs.cpp b/js/src/gc/FindSCCs-inl.h
similarity index 55%
rename from js/src/gc/FindSCCs.cpp
rename to js/src/gc/FindSCCs-inl.h
index 505279fe2edfec3274267456279f0bd897b4fa5f..403ed2c1f58c59eee882e2e618ddf999a24a5898 100644
--- a/js/src/gc/FindSCCs.cpp
+++ b/js/src/gc/FindSCCs-inl.h
@@ -4,14 +4,15 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "FindSCCs.h"
-
 #include "jsfriendapi.h"
 
+#include "gc/FindSCCs.h"
+
 namespace js {
 namespace gc {
 
-ComponentFinder::ComponentFinder(uintptr_t sl)
+template<class Node>
+ComponentFinder<Node>::ComponentFinder(uintptr_t sl)
   : clock(1),
     stack(NULL),
     firstComponent(NULL),
@@ -21,78 +22,50 @@ ComponentFinder::ComponentFinder(uintptr_t sl)
 {
 }
 
-ComponentFinder::~ComponentFinder()
+template<class Node>
+ComponentFinder<Node>::~ComponentFinder()
 {
     JS_ASSERT(!stack);
     JS_ASSERT(!firstComponent);
 }
 
+template<class Node>
 void
-ComponentFinder::addNode(GraphNodeBase *v)
+ComponentFinder<Node>::addNode(Node *v)
 {
     if (v->gcDiscoveryTime == Undefined) {
         JS_ASSERT(v->gcLowLink == Undefined);
-        JS_ASSERT(!v->gcNextGraphNode);
         processNode(v);
     }
 }
 
+template<class Node>
 void
-ComponentFinder::checkStackFull()
-{
-    /*
-     * Check for exceeding the size of the C stack.
-     *
-     * If this happens we give up and return all vertices in one group, by
-     * pushing them onto the output list with lowLink set to 1.
-     */
-
-    if (!stackFull) {
-        int stackDummy;
-        if (!JS_CHECK_STACK_SIZE(stackLimit, &stackDummy))
-            stackFull = true;
-    }
-
-    if (stackFull) {
-        GraphNodeBase *w;
-        while (stack) {
-            w = stack;
-            stack = w->gcNextGraphNode;
-
-            w->gcLowLink = 1;
-            w->gcNextGraphNode = firstComponent;
-            firstComponent = w;
-        }
-    }
-}
-
-void
-ComponentFinder::processNode(GraphNodeBase *v)
+ComponentFinder<Node>::processNode(Node *v)
 {
     v->gcDiscoveryTime = clock;
     v->gcLowLink = clock;
     ++clock;
 
-    JS_ASSERT(!v->gcNextGraphNode);
     v->gcNextGraphNode = stack;
     stack = v;
 
-    checkStackFull();
-    if (stackFull)
+    int stackDummy;
+    if (stackFull || !JS_CHECK_STACK_SIZE(stackLimit, &stackDummy)) {
+        stackFull = true;
         return;
+    }
 
-    GraphNodeBase *old = cur;
+    Node *old = cur;
     cur = v;
     cur->findOutgoingEdges(*this);
     cur = old;
 
-    if (stackFull) {
-        JS_ASSERT(!stack);
+    if (stackFull)
         return;
-    }
 
     if (v->gcLowLink == v->gcDiscoveryTime) {
-        GraphNodeBase *w;
+        Node *w;
         do {
             JS_ASSERT(stack);
             w = stack;
@@ -110,6 +83,12 @@ ComponentFinder::processNode(GraphNodeBase *v)
              */
             w->gcDiscoveryTime = Finished;
 
+            /* Figure out which group we're in. */
+            if (firstComponent && firstComponent->gcLowLink == w->gcLowLink)
+                w->gcNextGraphComponent = firstComponent->gcNextGraphComponent;
+            else
+                w->gcNextGraphComponent = firstComponent;
+
             /*
              * Prepend the component to the beginning of the output list to
              * reverse the list and achieve the desired order.
@@ -120,8 +99,9 @@ ComponentFinder::processNode(GraphNodeBase *v)
     }
 }
 
+template<class Node>
 void
-ComponentFinder::addEdgeTo(GraphNodeBase *w)
+ComponentFinder<Node>::addEdgeTo(Node *w)
 {
     if (w->gcDiscoveryTime == Undefined) {
         processNode(w);
@@ -131,45 +111,44 @@ ComponentFinder::addEdgeTo(GraphNodeBase *w)
     }
 }
 
-GraphNodeBase *
-ComponentFinder::getResultsList()
-{
-    JS_ASSERT(!stack);
-    GraphNodeBase *result = firstComponent;
-    firstComponent = NULL;
-    return result;
-}
-
-GraphNodeBase *
-ComponentFinder::removeFirstGroup(GraphNodeBase *resultsList)
+template<class Node>
+Node *
+ComponentFinder<Node>::getResultsList()
 {
-    /* Remove the first group from resultsList and return the new list head. */
+    if (stackFull) {
+        /*
+         * All nodes after the stack overflow are in |stack|. Put them all in
+         * one big component of their own.
+         */
+        Node *firstGoodComponent = firstComponent;
+        for (Node *v = stack; v; v = stack) {
+            stack = v->gcNextGraphNode;
+            v->gcNextGraphComponent = firstGoodComponent;
+            v->gcNextGraphNode = firstComponent;
+            firstComponent = v;
+        }
+        stackFull = false;
+    }
 
-    JS_ASSERT(resultsList);
+    JS_ASSERT(!stack);
 
-    GraphNodeBase *v = resultsList;
-    unsigned lowLink = v->gcLowLink;
+    Node *result = firstComponent;
+    firstComponent = NULL;
 
-    GraphNodeBase *last;
-    do {
+    for (Node *v = result; v; v = v->gcNextGraphNode) {
         v->gcDiscoveryTime = Undefined;
         v->gcLowLink = Undefined;
-        last = v;
-        v = v->gcNextGraphNode;
     }
-    while (v && v->gcLowLink == lowLink);
 
-    last->gcNextGraphNode = NULL;
-    return v;
+    return result;
 }
 
-void
-ComponentFinder::removeAllRemaining(GraphNodeBase *resultsList)
+template<class Node>
+/* static */ void
+ComponentFinder<Node>::mergeCompartmentGroups(Node *first)
 {
-    for (GraphNodeBase *v = resultsList; v; v = v->gcNextGraphNode) {
-        v->gcDiscoveryTime = Undefined;
-        v->gcLowLink = Undefined;
-    }
+    for (Node *v = first; v; v = v->gcNextGraphNode)
+        v->gcNextGraphComponent = NULL;
 }
 
 } /* namespace gc */
diff --git a/js/src/gc/FindSCCs.h b/js/src/gc/FindSCCs.h
index 571f77b737d6585df14fa843b7796e76a422936a..73fb6cbda340f6c4846ff4ff1a6428e2025a6ae9 100644
--- a/js/src/gc/FindSCCs.h
+++ b/js/src/gc/FindSCCs.h
@@ -12,50 +12,32 @@
 namespace js {
 namespace gc {
 
-class ComponentFinder;
-
-struct GraphNodeBase {
-    GraphNodeBase  *gcNextGraphNode;
+template<class Node>
+struct GraphNodeBase
+{
+    Node           *gcNextGraphNode;
+    Node           *gcNextGraphComponent;
     unsigned       gcDiscoveryTime;
     unsigned       gcLowLink;
 
     GraphNodeBase()
       : gcNextGraphNode(NULL),
+        gcNextGraphComponent(NULL),
         gcDiscoveryTime(0),
         gcLowLink(0) {}
 
-    virtual ~GraphNodeBase() {}
-    virtual void findOutgoingEdges(ComponentFinder& finder) = 0;
-};
-
-template <class T> static T *
-NextGraphNode(const T *current)
-{
-    const GraphNodeBase *node = current;
-    return static_cast<T *>(node->gcNextGraphNode);
-}
+    ~GraphNodeBase() {}
 
-template <class T> void
-AddGraphNode(T *&listHead, T *newFirstNode)
-{
-    GraphNodeBase *node = newFirstNode;
-    JS_ASSERT(!node->gcNextGraphNode);
-    node->gcNextGraphNode = listHead;
-    listHead = newFirstNode;
-}
-
-template <class T> static T *
-RemoveGraphNode(T *&listHead)
-{
-    GraphNodeBase *node = listHead;
-    if (!node)
+    Node *nextNodeInGroup() const {
+        if (gcNextGraphNode && gcNextGraphNode->gcNextGraphComponent == gcNextGraphComponent)
+            return gcNextGraphNode;
         return NULL;
+    }
 
-    T *result = listHead;
-    listHead = static_cast<T *>(node->gcNextGraphNode);
-    node->gcNextGraphNode = NULL;
-    return result;
-}
+    Node *nextGroup() const {
+        return gcNextGraphComponent;
+    }
+};
 
 /*
  * Find the strongly connected components of a graph using Tarjan's algorithm,
@@ -66,45 +48,35 @@ RemoveGraphNode(T *&listHead)
  *
  * struct MyGraphNode : public GraphNodeBase
  * {
- *     void findOutgoingEdges(ComponentFinder& finder)
+ *     void findOutgoingEdges(ComponentFinder<MyGraphNode> &finder)
  *     {
  *         for edge in my_outgoing_edges:
  *             if is_relevant(edge):
  *                 finder.addEdgeTo(edge.destination)
  *     }
  * }
+ *
+ * ComponentFinder<MyGraphNode> finder;
+ * finder.addNode(v);
  */
+template<class Node>
 class ComponentFinder
 {
   public:
     ComponentFinder(uintptr_t stackLimit);
     ~ComponentFinder();
-    void addNode(GraphNodeBase *v);
-    GraphNodeBase *getResultsList();
-
-    template <class T> static T *
-    getNextGroup(T *&resultsList) {
-        T *group = resultsList;
-        if (resultsList)
-            resultsList = static_cast<T *>(removeFirstGroup(resultsList));
-        return group;
-    }
 
-    template <class T> static T *
-    getAllRemaining(T *&resultsList) {
-        T *all = resultsList;
-        removeAllRemaining(resultsList);
-        resultsList = NULL;
-        return all;
-    }
+    /* Forces all nodes to be added to a single component. */
+    void useOneComponent() { stackFull = true; }
 
-  private:
-    static GraphNodeBase *removeFirstGroup(GraphNodeBase *resultsList);
-    static void removeAllRemaining(GraphNodeBase *resultsList);
+    void addNode(Node *v);
+    Node *getResultsList();
+
+    static void mergeCompartmentGroups(Node *first);
 
   public:
     /* Call from implementation of GraphNodeBase::findOutgoingEdges(). */
-    void addEdgeTo(GraphNodeBase *w);
+    void addEdgeTo(Node *w);
 
   private:
     /* Constant used to indicate an unprocessed vertex. */
@@ -113,14 +85,13 @@ class ComponentFinder
     /* Constant used to indicate an processed vertex that is no longer on the stack. */
     static const unsigned Finished = (unsigned)-1;
 
-    void processNode(GraphNodeBase *v);
-    void checkStackFull();
+    void processNode(Node *v);
 
   private:
     unsigned       clock;
-    GraphNodeBase  *stack;
-    GraphNodeBase  *firstComponent;
-    GraphNodeBase  *cur;
+    Node           *stack;
+    Node           *firstComponent;
+    Node           *cur;
     uintptr_t      stackLimit;
     bool           stackFull;
 };
diff --git a/js/src/jsapi-tests/testFindSCCs.cpp b/js/src/jsapi-tests/testFindSCCs.cpp
index 8028eac3b26c9388a261fd714108837c89a93079..29188e716400561aa6c20bec7ab693d364340745 100644
--- a/js/src/jsapi-tests/testFindSCCs.cpp
+++ b/js/src/jsapi-tests/testFindSCCs.cpp
@@ -11,27 +11,30 @@
 #include <string.h>
 #include <stdarg.h>
 
-#include "../gc/FindSCCs.h"
 #include "jscntxt.h"
 #include "jsgc.h"
 
+#include "gc/FindSCCs.h"
+
+#include "gc/FindSCCs-inl.h"
+
 static const unsigned MaxVertices = 10;
 
 using js::gc::GraphNodeBase;
 using js::gc::ComponentFinder;
 
-struct TestNode : public GraphNodeBase
+struct TestNode : public GraphNodeBase<TestNode>
 {
     unsigned   index;
     bool       hasEdge[MaxVertices];
 
-    void findOutgoingEdges(ComponentFinder& finder);
+    void findOutgoingEdges(ComponentFinder<TestNode> &finder);
 };
 
 static TestNode Vertex[MaxVertices];
 
 void
-TestNode::findOutgoingEdges(ComponentFinder& finder)
+TestNode::findOutgoingEdges(ComponentFinder<TestNode> &finder)
 {
     for (unsigned i = 0; i < MaxVertices; ++i) {
         if (hasEdge[i])
@@ -131,8 +134,8 @@ BEGIN_TEST(testFindSCCs)
 }
 
 unsigned vertex_count;
-ComponentFinder *finder;
-GraphNodeBase *resultsList;
+ComponentFinder<TestNode> *finder;
+TestNode *resultsList;
 
 void setup(unsigned count)
 {
@@ -152,7 +155,7 @@ void edge(unsigned src_index, unsigned dest_index)
 
 void run()
 {
-    finder = new ComponentFinder(rt->nativeStackLimit);
+    finder = new ComponentFinder<TestNode>(rt->nativeStackLimit);
     for (unsigned i = 0; i < vertex_count; ++i)
         finder->addNode(&Vertex[i]);
     resultsList = finder->getResultsList();
@@ -160,25 +163,26 @@ void run()
 
 bool group(int vertex, ...)
 {
-    TestNode *v = (TestNode *)ComponentFinder::getNextGroup(resultsList);
+    TestNode *v = resultsList;
 
     va_list ap;
     va_start(ap, vertex);
     while (vertex != -1) {
         CHECK(v != NULL);
         CHECK(v->index == unsigned(vertex));
-        v = (TestNode *)v->gcNextGraphNode;
+        v = v->nextNodeInGroup();
         vertex = va_arg(ap, int);
     }
     va_end(ap);
 
     CHECK(v == NULL);
+    resultsList = resultsList->nextGroup();
     return true;
 }
 
 bool remaining(int vertex, ...)
 {
-    TestNode *v = (TestNode *)ComponentFinder::getAllRemaining(resultsList);
+    TestNode *v = resultsList;
 
     va_list ap;
     va_start(ap, vertex);
@@ -191,6 +195,7 @@ bool remaining(int vertex, ...)
     va_end(ap);
 
     CHECK(v == NULL);
+    resultsList = NULL;
     return true;
 }
 
@@ -204,7 +209,7 @@ bool end()
 }
 END_TEST(testFindSCCs)
 
-struct TestNode2 : public GraphNodeBase
+struct TestNode2 : public GraphNodeBase<TestNode2>
 {
     TestNode2 *edge;
 
@@ -214,8 +219,7 @@ struct TestNode2 : public GraphNodeBase
     }
 
     void
-    findOutgoingEdges(ComponentFinder& finder)
-    {
+    findOutgoingEdges(ComponentFinder<TestNode2> &finder) {
         if (edge)
             finder.addEdgeTo(edge);
     }
@@ -236,27 +240,34 @@ BEGIN_TEST(testFindSCCsStackLimit)
      * is returned containing all the vertices.
      */
     const unsigned max = 1000000;
+    const unsigned initial = 10;
 
     TestNode2 *vertices = new TestNode2[max]();
-    for (unsigned i = 0; i < (max - 10); ++i)
+    for (unsigned i = initial; i < (max - 10); ++i)
         vertices[i].edge = &vertices[i + 1];
 
-    ComponentFinder finder(rt->nativeStackLimit);
+    ComponentFinder<TestNode2> finder(rt->nativeStackLimit);
     for (unsigned i = 0; i < max; ++i)
         finder.addNode(&vertices[i]);
 
-    GraphNodeBase *r = finder.getResultsList();
+    TestNode2 *r = finder.getResultsList();
     CHECK(r);
-    GraphNodeBase *v = finder.getNextGroup(r);
-    CHECK(v);
+    TestNode2 *v = r;
 
     unsigned count = 0;
     while (v) {
         ++count;
-        v = v->gcNextGraphNode;
+        v = v->nextNodeInGroup();
+    }
+    CHECK(count == max - initial);
+
+    count = 0;
+    v = r->nextGroup();
+    while (v) {
+        ++count;
+        CHECK(!v->nextNodeInGroup());
+        v = v->nextGroup();
     }
-    CHECK(count == max);
-    CHECK(finder.getNextGroup(r) == NULL);
 
     delete [] vertices;
     return true;
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index b89096587269a948173cb844cdf7562712167331..e019463e28d625ec81afd1686647a2f4388f6ffe 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -801,8 +801,8 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
     gcFoundBlackGrayEdges(false),
     gcSweepingCompartments(NULL),
     gcCompartmentGroupIndex(0),
-    gcRemainingCompartmentGroups(NULL),
-    gcCompartmentGroup(NULL),
+    gcCompartmentGroups(NULL),
+    gcCurrentCompartmentGroup(NULL),
     gcSweepPhase(0),
     gcSweepCompartment(NULL),
     gcSweepKindIndex(0),
diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
index 462a254c683cfa14d39a74bc030907161373b312..1bea1d1c47974cf3f9ca180cb72bdd7911205de0 100644
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -718,8 +718,8 @@ struct JSRuntime : js::RuntimeFriendFields
     /*
      * Incremental sweep state.
      */
-    JSCompartment       *gcRemainingCompartmentGroups;
-    JSCompartment       *gcCompartmentGroup;
+    JSCompartment       *gcCompartmentGroups;
+    JSCompartment       *gcCurrentCompartmentGroup;
     int                 gcSweepPhase;
     JSCompartment       *gcSweepCompartment;
     int                 gcSweepKindIndex;
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index 8f1460bf053e5abe51340a55a79e101fe8e25389..caa6182040363f6880201cbf81e0c6ed6bcbd33d 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -118,7 +118,7 @@ class AutoDebugModeGC;
 class DebugScopes;
 }
 
-struct JSCompartment : public js::gc::GraphNodeBase
+struct JSCompartment : public js::gc::GraphNodeBase<JSCompartment>
 {
     JSRuntime                    *rt;
     JSPrincipals                 *principals;
@@ -425,7 +425,7 @@ struct JSCompartment : public js::gc::GraphNodeBase
     void sweepCrossCompartmentWrappers();
     void purge();
 
-    virtual void findOutgoingEdges(js::gc::ComponentFinder& finder);
+    void findOutgoingEdges(js::gc::ComponentFinder<JSCompartment> &finder);
 
     void setGCLastBytes(size_t lastBytes, size_t lastMallocBytes, js::JSGCInvocationKind gckind);
     void reduceGCTriggerBytes(size_t amount);
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index ae82b64c98382cbefb594447fdee249a910202ce..6d639ba3d0cfb42c34d8a9bb809597c3777e960e 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -74,6 +74,7 @@
 
 #include "builtin/MapObject.h"
 #include "frontend/Parser.h"
+#include "gc/FindSCCs.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #include "gc/Memory.h"
@@ -90,11 +91,10 @@
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 
+#include "gc/FindSCCs-inl.h"
 #include "vm/ScopeObject-inl.h"
 #include "vm/String-inl.h"
 
-#include "gc/FindSCCs.h"
-
 #ifdef MOZ_VALGRIND
 # define JS_VALGRIND
 #endif
@@ -2069,29 +2069,26 @@ SweepBackgroundThings(JSRuntime* rt, bool onBackgroundThread)
      */
     FreeOp fop(rt, false);
     for (int phase = 0 ; phase < BackgroundPhaseCount ; ++phase) {
-        for (JSCompartment *c = rt->gcSweepingCompartments; c; c = NextGraphNode(c)) {
+        for (JSCompartment *comp = rt->gcSweepingCompartments; comp; comp = comp->gcNextGraphNode) {
             for (int index = 0 ; index < BackgroundPhaseLength[phase] ; ++index) {
                 AllocKind kind = BackgroundPhases[phase][index];
-                ArenaHeader *arenas = c->arenas.arenaListsToSweep[kind];
-                if (arenas) {
+                ArenaHeader *arenas = comp->arenas.arenaListsToSweep[kind];
+                if (arenas)
                     ArenaLists::backgroundFinalize(&fop, arenas, onBackgroundThread);
-                }
             }
         }
     }
 
-    while (rt->gcSweepingCompartments)
-        RemoveGraphNode(rt->gcSweepingCompartments);
+    rt->gcSweepingCompartments = NULL;
 }
 
 #ifdef JS_THREADSAFE
 static void
 AssertBackgroundSweepingFinished(JSRuntime *rt)
 {
+    JS_ASSERT(!rt->gcSweepingCompartments);
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
-        JS_ASSERT(!c->gcNextGraphNode);
         for (unsigned i = 0 ; i < FINALIZE_LIMIT ; ++i) {
-            JS_ASSERT(!c->gcNextGraphNode);
             JS_ASSERT(!c->arenas.arenaListsToSweep[i]);
             JS_ASSERT(c->arenas.doneBackgroundFinalize(AllocKind(i)));
         }
@@ -2760,11 +2757,7 @@ MarkGrayReferences(JSRuntime *rt)
     gcmarker->setMarkColorBlack();
 }
 
-#ifdef DEBUG
-static void
-ValidateIncrementalMarking(JSRuntime *rt);
-#endif
-
+#if 0
 #ifdef DEBUG
 static void
 ValidateIncrementalMarking(JSRuntime *rt)
@@ -2874,7 +2867,7 @@ ValidateIncrementalMarking(JSRuntime *rt)
 
     rt->gcIncrementalState = state;
 }
-
+#endif
 #endif
 
 static void
@@ -2909,7 +2902,7 @@ DropStringWrappers(JSRuntime *rt)
  */
 
 void
-JSCompartment::findOutgoingEdges(ComponentFinder& finder)
+JSCompartment::findOutgoingEdges(ComponentFinder<JSCompartment> &finder)
 {
     /*
      * Any compartment may have a pointer to an atom in the atoms
@@ -2959,32 +2952,27 @@ JSCompartment::findOutgoingEdges(ComponentFinder& finder)
 static void
 FindCompartmentGroups(JSRuntime *rt)
 {
-    JS_ASSERT(!rt->gcRemainingCompartmentGroups);
-    if (rt->gcIsIncremental) {
-        ComponentFinder finder(rt->nativeStackLimit);
-        for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
-            JS_ASSERT(c->isGCMarking());
-            finder.addNode(c);
-        }
-        rt->gcRemainingCompartmentGroups = static_cast<JSCompartment *>(finder.getResultsList());
-    } else {
-        for (GCCompartmentsIter c(rt); !c.done(); c.next())
-            AddGraphNode(rt->gcRemainingCompartmentGroups, c.get());
+    ComponentFinder<JSCompartment> finder(rt->nativeStackLimit);
+    if (!rt->gcIsIncremental)
+        finder.useOneComponent();
+
+    for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
+        JS_ASSERT(c->isGCMarking());
+        finder.addNode(c);
     }
+    rt->gcCompartmentGroups = finder.getResultsList();
+    rt->gcCurrentCompartmentGroup = rt->gcCompartmentGroups;
     rt->gcCompartmentGroupIndex = 0;
 }
 
 static void
 GetNextCompartmentGroup(JSRuntime *rt)
 {
-    JS_ASSERT(!rt->gcCompartmentGroup);
-    if (rt->gcIsIncremental)
-        rt->gcCompartmentGroup =
-            ComponentFinder::getNextGroup(rt->gcRemainingCompartmentGroups);
-    else
-        rt->gcCompartmentGroup =
-            ComponentFinder::getAllRemaining(rt->gcRemainingCompartmentGroups);
+    rt->gcCurrentCompartmentGroup = rt->gcCurrentCompartmentGroup->nextGroup();
     ++rt->gcCompartmentGroupIndex;
+
+    if (!rt->gcIsIncremental)
+        ComponentFinder<JSCompartment>::mergeCompartmentGroups(rt->gcCurrentCompartmentGroup);
 }
 
 /*
@@ -3252,11 +3240,6 @@ EndMarkingCompartmentGroup(JSRuntime *rt)
         c->setGCState(JSCompartment::Mark);
     }
 
-#ifdef DEBUG
-    if (rt->gcIsIncremental && rt->gcValidate && rt->gcCompartmentGroupIndex == 0)
-        ValidateIncrementalMarking(rt);
-#endif
-
     JS_ASSERT(rt->gcMarker.isDrained());
 }
 
@@ -3264,7 +3247,7 @@ static void
 BeginSweepingCompartmentGroup(JSRuntime *rt)
 {
     /*
-     * Begin sweeping the group of compartments in gcCompartmentGroup,
+     * Begin sweeping the group of compartments in gcCurrentCompartmentGroup,
      * performing actions that must be done before yielding to caller.
      */
 
@@ -3346,7 +3329,7 @@ BeginSweepingCompartmentGroup(JSRuntime *rt)
 #endif
 
     rt->gcSweepPhase = 0;
-    rt->gcSweepCompartment = rt->gcCompartmentGroup;
+    rt->gcSweepCompartment = rt->gcCurrentCompartmentGroup;
     rt->gcSweepKindIndex = 0;
 
     {
@@ -3360,7 +3343,7 @@ static void
 EndSweepingCompartmentGroup(JSRuntime *rt)
 {
     /* Update the GC state for compartments we have swept and unlink the list. */
-    while (JSCompartment *c = RemoveGraphNode(rt->gcCompartmentGroup)) {
+    for (GCCompartmentGroupIter c(rt); !c.done(); c.next()) {
         JS_ASSERT(c->isGCSweeping());
         c->setGCState(JSCompartment::Finished);
     }
@@ -3389,7 +3372,6 @@ BeginSweepPhase(JSRuntime *rt)
 #endif
 
 #ifdef DEBUG
-    JS_ASSERT(!rt->gcCompartmentGroup);
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         JS_ASSERT(!c->gcIncomingGrayPointers);
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
@@ -3401,7 +3383,6 @@ BeginSweepPhase(JSRuntime *rt)
 
     DropStringWrappers(rt);
     FindCompartmentGroups(rt);
-    GetNextCompartmentGroup(rt);
     EndMarkingCompartmentGroup(rt);
     BeginSweepingCompartmentGroup(rt);
 }
@@ -3439,26 +3420,26 @@ SweepPhase(JSRuntime *rt, SliceBudget &sliceBudget)
             gcstats::AutoPhase ap(rt->gcStats, FinalizePhaseStatsPhase[rt->gcSweepPhase]);
 
             for (; rt->gcSweepCompartment;
-                 rt->gcSweepCompartment = NextGraphNode(rt->gcSweepCompartment))
-                {
-                    JSCompartment *c = rt->gcSweepCompartment;
+                 rt->gcSweepCompartment = rt->gcSweepCompartment->nextNodeInGroup())
+            {
+                JSCompartment *c = rt->gcSweepCompartment;
 
-                    while (rt->gcSweepKindIndex < FinalizePhaseLength[rt->gcSweepPhase]) {
-                        AllocKind kind = FinalizePhases[rt->gcSweepPhase][rt->gcSweepKindIndex];
+                while (rt->gcSweepKindIndex < FinalizePhaseLength[rt->gcSweepPhase]) {
+                    AllocKind kind = FinalizePhases[rt->gcSweepPhase][rt->gcSweepKindIndex];
 
-                        if (!c->arenas.foregroundFinalize(&fop, kind, sliceBudget))
-                            return false;  /* Yield to the mutator. */
+                    if (!c->arenas.foregroundFinalize(&fop, kind, sliceBudget))
+                        return false;  /* Yield to the mutator. */
 
-                        ++rt->gcSweepKindIndex;
-                    }
-                    rt->gcSweepKindIndex = 0;
+                    ++rt->gcSweepKindIndex;
                 }
-            rt->gcSweepCompartment = rt->gcCompartmentGroup;
+                rt->gcSweepKindIndex = 0;
+            }
+            rt->gcSweepCompartment = rt->gcCurrentCompartmentGroup;
         }
 
         EndSweepingCompartmentGroup(rt);
         GetNextCompartmentGroup(rt);
-        if (!rt->gcCompartmentGroup)
+        if (!rt->gcCurrentCompartmentGroup)
             return true;  /* We're finished. */
         EndMarkingCompartmentGroup(rt);
         BeginSweepingCompartmentGroup(rt);
@@ -3548,8 +3529,10 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC)
 
     /* Set up list of compartments for sweeping of background things. */
     JS_ASSERT(!rt->gcSweepingCompartments);
-    for (GCCompartmentsIter c(rt); !c.done(); c.next())
-        AddGraphNode(rt->gcSweepingCompartments, c.get());
+    for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
+        c->gcNextGraphNode = rt->gcSweepingCompartments;
+        rt->gcSweepingCompartments = c;
+    }
 
     /* If not sweeping on background thread then we must do it here. */
     if (!rt->gcSweepOnBackgroundThread) {
@@ -3719,7 +3702,6 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason)
     for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
         JS_ASSERT(c->isCollecting());
         JS_ASSERT(!c->needsBarrier());
-        JS_ASSERT(!NextGraphNode(c.get()));
         JS_ASSERT(!c->gcLiveArrayBuffers);
         for (unsigned i = 0 ; i < FINALIZE_LIMIT ; ++i)
             JS_ASSERT(!c->arenas.arenaListsToSweep[i]);
diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h
index 7aea3e58c68e8be18a6a5c034f122417ed912fad..71303f28db603a383c2f2a47129f10c96200cd2f 100644
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -451,6 +451,7 @@ class GCCompartmentsIter {
     JSCompartment *operator->() const { return get(); }
 };
 
+/* Iterates over all compartments in the current compartment group. */
 class GCCompartmentGroupIter {
   private:
     JSCompartment *current;
@@ -458,14 +459,14 @@ class GCCompartmentGroupIter {
   public:
     GCCompartmentGroupIter(JSRuntime *rt) {
         JS_ASSERT(rt->isHeapBusy());
-        current = rt->gcCompartmentGroup;
+        current = rt->gcCurrentCompartmentGroup;
     }
 
-    bool done() const { return current == NULL; }
+    bool done() const { return !current; }
 
     void next() {
         JS_ASSERT(!done());
-        current = NextGraphNode(current);
+        current = current->nextNodeInGroup();
     }
 
     JSCompartment *get() const {
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index 17af3b65f53bbd4368fa7691d615c2a2de8b9545..363aca9af5c1213f3836764a813ab23ddbb62865 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -24,6 +24,7 @@
 #include "methodjit/Retcon.h"
 #include "js/Vector.h"
 
+#include "gc/FindSCCs-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
@@ -1560,7 +1561,7 @@ Debugger::detachAllDebuggersFromGlobal(FreeOp *fop, GlobalObject *global,
 }
 
 /* static */ void
-Debugger::findCompartmentEdges(JSCompartment *comp, js::gc::ComponentFinder &finder)
+Debugger::findCompartmentEdges(JSCompartment *comp, js::gc::ComponentFinder<JSCompartment> &finder)
 {
     /*
      * For debugger cross compartment wrappers, add edges in the opposite
@@ -1574,7 +1575,8 @@ Debugger::findCompartmentEdges(JSCompartment *comp, js::gc::ComponentFinder &fin
             continue;
         if (dbg->scripts.hasKeyInCompartment(comp) ||
             dbg->objects.hasKeyInCompartment(comp) ||
-            dbg->environments.hasKeyInCompartment(comp)) {
+            dbg->environments.hasKeyInCompartment(comp))
+        {
             finder.addEdgeTo(w);
         }
     }
diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h
index 9450159b5b13d5b791721c09ee6fff492690ecc4..e07bb5df0d0d96f58f0841a2884c3509e3ed2f2a 100644
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -378,7 +378,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
                                              GlobalObjectSet::Enum *compartmentEnum);
     static unsigned gcGrayLinkSlot();
     static bool isDebugWrapper(RawObject o);
-    static void findCompartmentEdges(JSCompartment *v, js::gc::ComponentFinder &finder);
+    static void findCompartmentEdges(JSCompartment *v, gc::ComponentFinder<JSCompartment> &finder);
 
     static inline JSTrapStatus onEnterFrame(JSContext *cx, Value *vp);
     static inline bool onLeaveFrame(JSContext *cx, bool ok);