Bug 729238 - Save and restore weakmap list during marking validation (r=igor)
authorBill McCloskey <wmccloskey@mozilla.com>
Mon, 27 Feb 2012 09:48:35 -0800
changeset 87848 246c77eef7cbb6febbdd3c7660b6143eb0093e99
parent 87847 0714ec049da2e9a9a6f7bf6f2cf7233528d1e76e
child 87849 00929ec6099170cb7c22169bf9ea5e7db85630f2
push id22160
push usermbrubeck@mozilla.com
push dateTue, 28 Feb 2012 17:21:33 +0000
treeherdermozilla-central@dde4e0089a18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersigor
bugs729238
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 729238 - Save and restore weakmap list during marking validation (r=igor)
js/src/jsgc.cpp
js/src/jsweakmap.cpp
js/src/jsweakmap.h
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3073,37 +3073,45 @@ 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 */
+    /* 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;
     }
 
+    /* Save the existing weakmaps. */
+    WeakMapVector weakmaps;
+    if (!WeakMapBase::saveWeakMapList(rt, weakmaps))
+        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();
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
 
     MarkRuntime(gcmarker, true);
     SliceBudget budget;
@@ -3141,16 +3149,20 @@ ValidateIncrementalMarking(JSContext *cx
                 JS_ASSERT_IF(bitmap->isMarked(cell, BLACK), incBitmap.isMarked(cell, BLACK));
                 thing += Arena::thingSize(kind);
             }
         }
 
         memcpy(bitmap->bitmap, incBitmap.bitmap, sizeof(incBitmap.bitmap));
     }
 
+    /* Restore the weak map list. */
+    WeakMapBase::resetWeakMapList(rt);
+    WeakMapBase::restoreWeakMapList(rt, weakmaps);
+
     rt->gcIncrementalState = state;
 }
 #endif
 
 static void
 SweepPhase(JSContext *cx, JSGCInvocationKind gckind)
 {
     JSRuntime *rt = cx->runtime;
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -97,16 +97,40 @@ WeakMapBase::resetWeakMapList(JSRuntime 
     rt->gcWeakMapList = NULL;
     while (m) {
         WeakMapBase *n = m->next;
         m->next = WeakMapNotInList;
         m = n;
     }
 }
 
+bool
+WeakMapBase::saveWeakMapList(JSRuntime *rt, WeakMapVector &vector)
+{
+    WeakMapBase *m = rt->gcWeakMapList;
+    while (m) {
+        if (!vector.append(m))
+            return false;
+        m = m->next;
+    }
+    return true;
+}
+
+void
+WeakMapBase::restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector)
+{
+    JS_ASSERT(!rt->gcWeakMapList);
+    for (WeakMapBase **p = vector.begin(); p != vector.end(); p++) {
+        WeakMapBase *m = *p;
+        JS_ASSERT(m->next == WeakMapNotInList);
+        m->next = rt->gcWeakMapList;
+        rt->gcWeakMapList = m;
+    }
+}
+
 } /* namespace js */
 
 typedef WeakMap<HeapPtr<JSObject>, HeapValue> ObjectValueMap;
 
 static ObjectValueMap *
 GetObjectMap(JSObject *obj)
 {
     JS_ASSERT(obj->isWeakMap());
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -104,16 +104,18 @@ template <class Type> class DefaultMarkP
 
 // A policy template holding default tracing algorithms for common type combinations. This
 // provides default types for WeakMap's TracePolicy template parameter.
 template <class Key, class Value> class DefaultTracePolicy;
 
 // The value for the next pointer for maps not in the map list.
 static WeakMapBase * const WeakMapNotInList = reinterpret_cast<WeakMapBase *>(1);
 
+typedef Vector<WeakMapBase *, 0, SystemAllocPolicy> WeakMapVector;
+
 // Common base class for all WeakMap specializations. The collector uses this to call
 // their markIteratively and sweep methods.
 class WeakMapBase {
   public:
     WeakMapBase(JSObject *memOf) : memberOf(memOf), next(WeakMapNotInList) { }
     virtual ~WeakMapBase() { }
 
     void trace(JSTracer *tracer) {
@@ -156,16 +158,20 @@ class WeakMapBase {
     // Trace all delayed weak map bindings. Used by the cycle collector.
     static void traceAllMappings(WeakMapTracer *tracer);
 
     void check() { JS_ASSERT(next == WeakMapNotInList); }
 
     // Remove everything from the live weak map list.
     static void resetWeakMapList(JSRuntime *rt);
 
+    // Save and restore the live weak map list to a vector.
+    static bool saveWeakMapList(JSRuntime *rt, WeakMapVector &vector);
+    static void restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector);
+
   protected:
     // Instance member functions called by the above. Instantiations of WeakMap override
     // these with definitions appropriate for their Key and Value types.
     virtual void nonMarkingTrace(JSTracer *tracer) = 0;
     virtual bool markIteratively(JSTracer *tracer) = 0;
     virtual void sweep(JSTracer *tracer) = 0;
     virtual void traceMappings(WeakMapTracer *tracer) = 0;