Bug 1017165 - Part 2: Let ArenaLists track swept arenas between slices and extend ArenaIter to walk incrementally swept arenas as well. r=billm
authorEmanuel Hoogeveen <emanuel.hoogeveen@gmail.com>
Wed, 16 Jul 2014 17:10:00 +0200
changeset 216507 42d1935444659dee9ff9ebd21e5dafdadc050fbc
parent 216506 bbfa802abc93376c8aa36fb1ee8560e1391e9d23
child 216508 f92e4d13b3c6e20501703994f8c8d7fe0618ffc4
child 216582 4aa73f5db7b5e48d194b69b4b2ecf51f54ddf383
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1017165
milestone33.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 1017165 - Part 2: Let ArenaLists track swept arenas between slices and extend ArenaIter to walk incrementally swept arenas as well. r=billm
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4352,18 +4352,24 @@ GCRuntime::beginSweepPhase(bool lastGC)
     endMarkingZoneGroup();
     beginSweepingZoneGroup();
 }
 
 bool
 ArenaLists::foregroundFinalize(FreeOp *fop, AllocKind thingKind, SliceBudget &sliceBudget,
                                SortedArenaList &sweepList)
 {
-    if (!FinalizeArenas(fop, &arenaListsToSweep[thingKind], sweepList, thingKind, sliceBudget))
+    if (!FinalizeArenas(fop, &arenaListsToSweep[thingKind], sweepList, thingKind, sliceBudget)) {
+        incrementalSweptArenaKind = thingKind;
+        incrementalSweptArenas = sweepList.toArenaList();
         return false;
+    }
+
+    // Clear any previous incremental sweep state we may have saved.
+    incrementalSweptArenas.clear();
 
     // Join |arenaLists[thingKind]| and |sweepList| into a single list.
     ArenaList finalized = sweepList.toArenaList();
     arenaLists[thingKind] = finalized.insertListWithCursorAtEnd(arenaLists[thingKind]);
 
     return true;
 }
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -690,27 +690,32 @@ class ArenaLists
         BackgroundFinalizeState;
 
     BackgroundFinalizeState backgroundFinalizeState[FINALIZE_LIMIT];
 
   public:
     /* For each arena kind, a list of arenas remaining to be swept. */
     ArenaHeader *arenaListsToSweep[FINALIZE_LIMIT];
 
+    /* During incremental sweeping, a list of the arenas already swept. */
+    unsigned incrementalSweptArenaKind;
+    ArenaList incrementalSweptArenas;
+
     /* Shape arenas to be swept in the foreground. */
     ArenaHeader *gcShapeArenasToSweep;
 
   public:
     ArenaLists() {
         for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
             freeLists[i].initAsEmpty();
         for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
             backgroundFinalizeState[i] = BFS_DONE;
         for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
             arenaListsToSweep[i] = nullptr;
+        incrementalSweptArenaKind = FINALIZE_LIMIT;
         gcShapeArenasToSweep = nullptr;
     }
 
     ~ArenaLists() {
         for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
             /*
              * We can only call this during the shutdown after the last GC when
              * the background finalization is disabled.
@@ -718,16 +723,22 @@ class ArenaLists
             JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE);
             ArenaHeader *next;
             for (ArenaHeader *aheader = arenaLists[i].head(); aheader; aheader = next) {
                 // Copy aheader->next before releasing.
                 next = aheader->next;
                 aheader->chunk()->releaseArena(aheader);
             }
         }
+        ArenaHeader *next;
+        for (ArenaHeader *aheader = incrementalSweptArenas.head(); aheader; aheader = next) {
+            // Copy aheader->next before releasing.
+            next = aheader->next;
+            aheader->chunk()->releaseArena(aheader);
+        }
     }
 
     static uintptr_t getFreeListOffset(AllocKind thingKind) {
         uintptr_t offset = offsetof(ArenaLists, freeLists);
         return offset + thingKind * sizeof(FreeList);
     }
 
     const FreeList *getFreeList(AllocKind thingKind) const {
@@ -737,16 +748,22 @@ class ArenaLists
     ArenaHeader *getFirstArena(AllocKind thingKind) const {
         return arenaLists[thingKind].head();
     }
 
     ArenaHeader *getFirstArenaToSweep(AllocKind thingKind) const {
         return arenaListsToSweep[thingKind];
     }
 
+    ArenaHeader *getFirstSweptArena(AllocKind thingKind) const {
+        if (thingKind != incrementalSweptArenaKind)
+            return nullptr;
+        return incrementalSweptArenas.head();
+    }
+
     ArenaHeader *getArenaAfterCursor(AllocKind thingKind) const {
         return arenaLists[thingKind].arenaAfterCursor();
     }
 
     bool arenaListsAreEmpty() const {
         for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
             /*
              * The arena cannot be empty if the background finalization is not yet
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -132,34 +132,42 @@ GCRuntime::poke()
     if (zealMode == ZealPokeValue)
         nextScheduled = 1;
 #endif
 }
 
 class ArenaIter
 {
     ArenaHeader *aheader;
-    ArenaHeader *remainingHeader;
+    ArenaHeader *unsweptHeader;
+    ArenaHeader *sweptHeader;
 
   public:
     ArenaIter() {
         aheader = nullptr;
-        remainingHeader = nullptr;
+        unsweptHeader = nullptr;
+        sweptHeader = nullptr;
     }
 
     ArenaIter(JS::Zone *zone, AllocKind kind) {
         init(zone, kind);
     }
 
     void init(Allocator *allocator, AllocKind kind) {
         aheader = allocator->arenas.getFirstArena(kind);
-        remainingHeader = allocator->arenas.getFirstArenaToSweep(kind);
+        unsweptHeader = allocator->arenas.getFirstArenaToSweep(kind);
+        sweptHeader = allocator->arenas.getFirstSweptArena(kind);
+        if (!unsweptHeader) {
+            unsweptHeader = sweptHeader;
+            sweptHeader = nullptr;
+        }
         if (!aheader) {
-            aheader = remainingHeader;
-            remainingHeader = nullptr;
+            aheader = unsweptHeader;
+            unsweptHeader = sweptHeader;
+            sweptHeader = nullptr;
         }
     }
 
     void init(JS::Zone *zone, AllocKind kind) {
         init(&zone->allocator, kind);
     }
 
     bool done() const {
@@ -169,18 +177,19 @@ class ArenaIter
     ArenaHeader *get() const {
         return aheader;
     }
 
     void next() {
         JS_ASSERT(!done());
         aheader = aheader->next;
         if (!aheader) {
-            aheader = remainingHeader;
-            remainingHeader = nullptr;
+            aheader = unsweptHeader;
+            unsweptHeader = sweptHeader;
+            sweptHeader = nullptr;
         }
     }
 };
 
 class ArenaCellIterImpl
 {
     // These three are set in initUnsynchronized().
     size_t firstThingOffset;