Bug 1001159 (part 2) - Rewrite ArenaCellIterImpl. r=billm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 29 Apr 2014 17:59:03 -0700
changeset 181539 967225ce2e6830d6b2d1bbdf0dff995f796fc17e
parent 181538 a973436eb53b2d977a5d9257c005fba6fb71befa
child 181540 d3078c201af647e096783ca0ab9cbb4059b68081
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersbillm
bugs1001159
milestone32.0a1
Bug 1001159 (part 2) - Rewrite ArenaCellIterImpl. r=billm.
js/src/jsgcinlines.h
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -117,33 +117,24 @@ GCPoke(JSRuntime *rt)
 
 class ArenaIter
 {
     ArenaHeader *aheader;
     ArenaHeader *remainingHeader;
 
   public:
     ArenaIter() {
-        init();
+        aheader = nullptr;
+        remainingHeader = nullptr;
     }
 
     ArenaIter(JS::Zone *zone, AllocKind kind) {
         init(zone, kind);
     }
 
-    void init() {
-        aheader = nullptr;
-        remainingHeader = nullptr;
-    }
-
-    void init(ArenaHeader *aheaderArg) {
-        aheader = aheaderArg;
-        remainingHeader = nullptr;
-    }
-
     void init(JS::Zone *zone, AllocKind kind) {
         aheader = zone->allocator.arenas.getFirstArena(kind);
         remainingHeader = zone->allocator.arenas.getFirstArenaToSweep(kind);
         if (!aheader) {
             aheader = remainingHeader;
             remainingHeader = nullptr;
         }
     }
@@ -162,80 +153,86 @@ class ArenaIter
             aheader = remainingHeader;
             remainingHeader = nullptr;
         }
     }
 };
 
 class ArenaCellIterImpl
 {
+    // These three are set in init().
     size_t firstThingOffset;
     size_t thingSize;
-    ArenaIter aiter;
-    FreeSpan firstSpan;
-    const FreeSpan *span;
+#ifdef DEBUG
+    bool isInited;
+#endif
+
+    // These three are set in reset() (which is called by init()).
+    FreeSpan span;
     uintptr_t thing;
-    Cell *cell;
-
-  protected:
-    ArenaCellIterImpl() {
-    }
+    uintptr_t limit;
 
-    void initSpan(JS::Zone *zone, AllocKind kind) {
-        JS_ASSERT(zone->allocator.arenas.isSynchronizedFreeList(kind));
-        firstThingOffset = Arena::firstThingOffset(kind);
-        thingSize = Arena::thingSize(kind);
-        firstSpan.initAsEmpty();
-        span = &firstSpan;
-        thing = span->first;
-    }
-
-    void init(ArenaHeader *singleAheader) {
-        initSpan(singleAheader->zone, singleAheader->getAllocKind());
-        aiter.init(singleAheader);
-        next();
-        aiter.init();
+    // Upon entry, |thing| points to any thing (free or used) and finds the
+    // first used thing, which may be |thing|.
+    void moveForwardIfFree() {
+        JS_ASSERT(!done());
+        if (thing == span.first) {
+            if (span.hasNext()) {
+                thing = span.last + thingSize;
+                span = *span.nextSpan();
+            } else {
+                thing = limit;
+            }
+        }
     }
 
   public:
+    ArenaCellIterImpl() {}
+
+    void init(ArenaHeader *aheader) {
+        AllocKind kind = aheader->getAllocKind();
+#ifdef DEBUG
+        JS_ASSERT(aheader->zone->allocator.arenas.isSynchronizedFreeList(kind));
+        isInited = true;
+#endif
+        firstThingOffset = Arena::firstThingOffset(kind);
+        thingSize = Arena::thingSize(kind);
+        reset(aheader);
+    }
+
+    // Use this to move from an Arena of a particular kind to another Arena of
+    // the same kind.
+    void reset(ArenaHeader *aheader) {
+        JS_ASSERT(isInited);
+        span = aheader->getFirstFreeSpan();
+        uintptr_t arenaAddr = aheader->arenaAddress();
+        thing = arenaAddr + firstThingOffset;
+        limit = arenaAddr + ArenaSize;
+        moveForwardIfFree();
+    }
+
     bool done() const {
-        return !cell;
+        return thing == limit;
+    }
+
+    Cell *getCell() const {
+        JS_ASSERT(!done());
+        return reinterpret_cast<Cell *>(thing);
     }
 
     template<typename T> T *get() const {
         JS_ASSERT(!done());
-        return static_cast<T *>(cell);
-    }
-
-    Cell *getCell() const {
-        JS_ASSERT(!done());
-        return cell;
+        return static_cast<T *>(getCell());
     }
 
     void next() {
-        for (;;) {
-            if (thing != span->first)
-                break;
-            if (MOZ_LIKELY(span->hasNext())) {
-                thing = span->last + thingSize;
-                span = span->nextSpan();
-                break;
-            }
-            if (aiter.done()) {
-                cell = nullptr;
-                return;
-            }
-            ArenaHeader *aheader = aiter.get();
-            firstSpan = aheader->getFirstFreeSpan();
-            span = &firstSpan;
-            thing = aheader->arenaAddress() | firstThingOffset;
-            aiter.next();
-        }
-        cell = reinterpret_cast<Cell *>(thing);
+        MOZ_ASSERT(!done());
         thing += thingSize;
+        if (thing < limit)
+            moveForwardIfFree();
     }
 };
 
 class ArenaCellIterUnderGC : public ArenaCellIterImpl
 {
   public:
     ArenaCellIterUnderGC(ArenaHeader *aheader) {
         JS_ASSERT(aheader->zone->runtimeFromAnyThread()->isHeapBusy());