Bug 730148 - Handle OOM better in ValidateIncrementalMarking (r=igor)
authorBill McCloskey <wmccloskey@mozilla.com>
Fri, 24 Feb 2012 10:46:31 -0800
changeset 87649 00ab2b295e8415d934f8022b53e86b25d04eee80
parent 87648 fad8d2718cd07645060e2e5a67064085e1548d9d
child 87650 b65b50546776fea729c8092ddf6daf60eaa791a1
push id6447
push userwmccloskey@mozilla.com
push dateFri, 24 Feb 2012 18:47:33 +0000
treeherdermozilla-inbound@00ab2b295e84 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersigor
bugs730148
milestone13.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 730148 - Handle OOM better in ValidateIncrementalMarking (r=igor)
js/src/jsgc.cpp
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3064,57 +3064,66 @@ EndMarkPhase(JSContext *cx)
     }
 #endif
 }
 
 #ifdef DEBUG
 static void
 ValidateIncrementalMarking(JSContext *cx)
 {
+    typedef HashMap<Chunk *, uintptr_t *, GCChunkHasher, SystemAllocPolicy> BitmapMap;
+    BitmapMap map;
+    if (!map.init())
+        return;
+
     JSRuntime *rt = cx->runtime;
     FullGCMarker *gcmarker = &rt->gcMarker;
 
+    /* Save existing mark bits */
+    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
+        ChunkBitmap *bitmap = &r.front()->bitmap;
+        uintptr_t *entry = (uintptr_t *)js_malloc(sizeof(bitmap->bitmap));
+        if (!entry)
+            return;
+
+        memcpy(entry, bitmap->bitmap, sizeof(bitmap->bitmap));
+        if (!map.putNew(r.front(), entry))
+            return;
+    }
+
+    /*
+     * After this point, the function should run to completion, so we shouldn't
+     * do anything fallible.
+     */
+
+    /* Re-do all the marking, but non-incrementally. */
     js::gc::State state = rt->gcIncrementalState;
     rt->gcIncrementalState = NO_INCREMENTAL;
 
     /* As we're re-doing marking, we need to reset the weak map list. */
     WeakMapBase::resetWeakMapList(rt);
 
     JS_ASSERT(gcmarker->isDrained());
     gcmarker->reset();
 
-    typedef HashMap<Chunk *, uintptr_t *> BitmapMap;
-    BitmapMap map(cx);
-    map.init();
-
-    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
-        ChunkBitmap *bitmap = &r.front()->bitmap;
-        uintptr_t *entry = (uintptr_t *)js_malloc(sizeof(bitmap->bitmap));
-        if (entry)
-            memcpy(entry, bitmap->bitmap, sizeof(bitmap->bitmap));
-        map.putNew(r.front(), entry);
-    }
-
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
 
     MarkRuntime(gcmarker, true);
     SliceBudget budget;
     rt->gcMarker.drainMarkStack(budget);
     MarkGrayAndWeak(cx);
 
+    /* Now verify that we have the same mark bits as before. */
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
         Chunk *chunk = r.front();
         ChunkBitmap *bitmap = &chunk->bitmap;
         uintptr_t *entry = map.lookup(r.front())->value;
         ChunkBitmap incBitmap;
 
-        if (!entry)
-            continue;
-
         memcpy(incBitmap.bitmap, entry, sizeof(incBitmap.bitmap));
         js_free(entry);
 
         for (size_t i = 0; i < ArenasPerChunk; i++) {
             Arena *arena = &chunk->arenas[i];
             if (!arena->aheader.allocated())
                 continue;
             if (rt->gcCurrentCompartment && arena->aheader.compartment != rt->gcCurrentCompartment)