Bug 1275448 - Don't crash on shutdown due to non-empty type descriptors set if we leak r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 22 Jul 2016 13:57:10 +0100
changeset 331426 c9abfc5925a2af00d0eb3e61a6316efc7e83f9de
parent 331425 31163bfc3cb4f849c25c9f756bdfe3639b45b9fe
child 331427 82e2bfbaf3270ed3237e340e708d6f7838bfcc7e
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1275448
milestone50.0a1
Bug 1275448 - Don't crash on shutdown due to non-empty type descriptors set if we leak r=sfink
js/src/gc/Zone.cpp
js/src/jsgc.cpp
js/src/jsgc.h
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -53,18 +53,16 @@ JS::Zone::Zone(JSRuntime* rt)
 
     AutoLockGC lock(rt);
     threshold.updateAfterGC(8192, GC_NORMAL, rt->gc.tunables, rt->gc.schedulingState, lock);
     setGCMaxMallocBytes(rt->gc.maxMallocBytesAllocated() * 0.9);
 }
 
 Zone::~Zone()
 {
-    MOZ_ASSERT_IF(typeDescrObjects.initialized(), typeDescrObjects.empty());
-
     JSRuntime* rt = runtimeFromMainThread();
     if (this == rt->gc.systemZone)
         rt->gc.systemZone = nullptr;
 
     js_delete(debuggers);
     js_delete(jitZone_);
 }
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3548,23 +3548,24 @@ GCRuntime::sweepZones(FreeOp* fop, bool 
             {
                 // We have just finished sweeping, so we should have freed any
                 // empty arenas back to their Chunk for future allocation.
                 zone->arenas.checkEmptyFreeLists();
 
                 // We are about to delete the Zone; this will leave the Zone*
                 // in the arena header dangling if there are any arenas
                 // remaining at this point.
-                zone->arenas.checkEmptyArenaLists();
+                mozilla::DebugOnly<bool> arenasEmpty = zone->arenas.checkEmptyArenaLists();
 
                 if (callback)
                     callback(zone);
 
                 zone->sweepCompartments(fop, false, destroyingRuntime);
                 MOZ_ASSERT(zone->compartments.empty());
+                MOZ_ASSERT_IF(arenasEmpty, zone->typeDescrObjects.empty());
                 fop->delete_(zone);
                 stats.sweptZone();
                 continue;
             }
             zone->sweepCompartments(fop, true, destroyingRuntime);
         }
         *write++ = zone;
     }
@@ -3582,31 +3583,34 @@ FOR_EACH_ALLOCKIND(MAKE_CASE)
 #undef MAKE_CASE
 
       default:
         MOZ_CRASH("Unknown AllocKind in AllocKindToAscii");
     }
 }
 #endif // DEBUG
 
-void
+bool
 ArenaLists::checkEmptyArenaList(AllocKind kind)
 {
+    bool empty = true;
 #ifdef DEBUG
     if (!arenaLists[kind].isEmpty()) {
         for (Arena* current = arenaLists[kind].head(); current; current = current->next) {
             for (ArenaCellIterUnderFinalize i(current); !i.done(); i.next()) {
                 Cell* t = i.get<Cell>();
                 MOZ_ASSERT(t->asTenured().isMarked(), "unmarked cells should have been finalized");
                 fprintf(stderr, "ERROR: GC found live Cell %p of kind %s at shutdown\n",
                         t, AllocKindToAscii(kind));
+                empty = false;
             }
         }
     }
 #endif // DEBUG
+    return empty;
 }
 
 void
 GCRuntime::purgeRuntime(AutoLockForExclusiveAccess& lock)
 {
     for (GCCompartmentsIter comp(rt); !comp.done(); comp.next())
         comp->purge();
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -736,28 +736,32 @@ class ArenaLists
 
     void checkEmptyFreeLists() {
 #ifdef DEBUG
         for (auto i : AllAllocKinds())
             checkEmptyFreeList(i);
 #endif
     }
 
-    void checkEmptyArenaLists() {
+    bool checkEmptyArenaLists() {
+        bool empty = true;
 #ifdef DEBUG
-        for (auto i : AllAllocKinds())
-            checkEmptyArenaList(i);
+        for (auto i : AllAllocKinds()) {
+            if (!checkEmptyArenaList(i))
+                empty = false;
+        }
 #endif
+        return empty;
     }
 
     void checkEmptyFreeList(AllocKind kind) {
         MOZ_ASSERT(freeLists[kind]->isEmpty());
     }
 
-    void checkEmptyArenaList(AllocKind kind);
+    bool checkEmptyArenaList(AllocKind kind);
 
     bool relocateArenas(Zone* zone, Arena*& relocatedListOut, JS::gcreason::Reason reason,
                         SliceBudget& sliceBudget, gcstats::Statistics& stats);
 
     void queueForegroundObjectsForSweep(FreeOp* fop);
     void queueForegroundThingsForSweep(FreeOp* fop);
 
     void mergeForegroundSweptObjectArenas();