Bug 1146662 - Refactor ArenasToUpdate::next to work with a range-based for loop. r=jonco
authorEmanuel Hoogeveen <emanuel.hoogeveen@gmail.com>
Thu, 26 Mar 2015 09:50:00 -0400
changeset 264968 176ade0f680db91f93879209d7ebc3458cecbf96
parent 264967 bd86bb29b687a27ee47af8942b4014d50b43725c
child 264969 f93153e7329e38d65c835dd463b32a043012de6f
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1146662
milestone39.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 1146662 - Refactor ArenasToUpdate::next to work with a range-based for loop. r=jonco
js/src/gc/Heap.h
js/src/jsgc.cpp
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -108,31 +108,49 @@ enum class AllocKind {
     JITCODE,
     LIMIT,
     LAST = LIMIT - 1
 };
 
 static_assert(uint8_t(AllocKind::OBJECT0) == 0, "Please check AllocKind iterations and comparisons"
     " of the form |kind <= AllocKind::OBJECT_LAST| to ensure their range is still valid!");
 
+// Returns a sequence for use in a range-based for loop,
+// to iterate over all alloc kinds.
 inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT))
 AllAllocKinds()
 {
     return mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT);
 }
 
+// Returns a sequence for use in a range-based for loop,
+// to iterate over all object alloc kinds.
 inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT))
 ObjectAllocKinds()
 {
     return mozilla::MakeEnumeratedRange<int>(AllocKind::OBJECT0, AllocKind::OBJECT_LIMIT);
 }
 
+// Returns a sequence for use in a range-based for loop,
+// to iterate over alloc kinds from |first| to |limit|, exclusive.
+inline decltype(mozilla::MakeEnumeratedRange<int>(AllocKind::FIRST, AllocKind::LIMIT))
+SomeAllocKinds(AllocKind first = AllocKind::FIRST, AllocKind limit = AllocKind::LIMIT)
+{
+    MOZ_ASSERT(limit <= AllocKind::LIMIT);
+    MOZ_ASSERT(first <= limit);
+    return mozilla::MakeEnumeratedRange<int>(first, limit);
+}
+
+// AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
+// with each index corresponding to a particular alloc kind.
 template<typename ValueType> using AllAllocKindArray =
     mozilla::EnumeratedArray<AllocKind, AllocKind::LIMIT, ValueType>;
 
+// ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
+// with each index corresponding to a particular object alloc kind.
 template<typename ValueType> using ObjectAllocKindArray =
     mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;
 
 static inline JSGCTraceKind
 MapAllocToTraceKind(AllocKind kind)
 {
     static const JSGCTraceKind map[] = {
         JSTRACE_OBJECT,       /* AllocKind::OBJECT0 */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2298,17 +2298,17 @@ struct ArenasToUpdate
     bool done() { return initialized && arena == nullptr; }
     ArenaHeader* next(AutoLockHelperThreadState& lock);
     ArenaHeader *getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned max);
 
   private:
     bool initialized;
     KindsToUpdate kinds;
     Zone *zone;          // Zone to process
-    unsigned kind;       // Current alloc kind to process
+    AllocKind kind;      // Current alloc kind to process
     ArenaHeader *arena;  // Next arena to process
 
     bool shouldProcessKind(AllocKind kind);
 };
 
 bool ArenasToUpdate::shouldProcessKind(AllocKind kind)
 {
     MOZ_ASSERT(kind < AllocKind::LIMIT);
@@ -2344,42 +2344,46 @@ ArenasToUpdate::ArenasToUpdate(Zone *zon
     MOZ_ASSERT(kinds && !(kinds & ~ALL));
 }
 
 ArenaHeader *
 ArenasToUpdate::next(AutoLockHelperThreadState& lock)
 {
     // Find the next arena to update.
     //
-    // Note that this uses a generator-like arrangement. The first time this is
-    // called, |initialized| is false and the for-loops below are entered in the
-    // normal way, returning the first arena found. In subsequent invocations we
-    // jump directly into the body of the for loops just after the previous
-    // return. All state is stored in class members and so preserved between
-    // invocations.
+    // The first time this is called, we initialize the kind and arena and loop
+    // over all alloc kinds, returning the first arena found. In subsequent
+    // invocations we go through the remaining arenas first, then increment the
+    // kind manually before looping over the remaining kinds.
 
     if (initialized) {
         MOZ_ASSERT(arena);
-        MOZ_ASSERT(shouldProcessKind(AllocKind(kind)));
+        MOZ_ASSERT(shouldProcessKind(kind));
         MOZ_ASSERT(zone);
-        goto resumePoint;
-    }
-
-    initialized = true;
-    for (kind = 0; kind < size_t(AllocKind::LIMIT); ++kind) {
-        if (shouldProcessKind(AllocKind(kind))) {
-            for (arena = zone->arenas.getFirstArena(AllocKind(kind));
-                 arena;
-                 arena = arena->next)
-            {
+        arena = arena->next;
+        if (arena)
+            return arena;
+        kind = AllocKind(uint8_t(kind) + 1);
+    } else {
+        initialized = true;
+        arena = nullptr;
+        kind = AllocKind::FIRST;
+    }
+
+    for (auto i : SomeAllocKinds(kind)) {
+        if (shouldProcessKind(i)) {
+            arena = zone->arenas.getFirstArena(i);
+            if (arena) {
+                kind = i;
                 return arena;
-              resumePoint:;
             }
         }
     }
+
+    kind = AllocKind::LIMIT;
     zone = nullptr;
     return nullptr;
 }
 
 ArenaHeader *
 ArenasToUpdate::getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned count)
 {
     if (!zone)