Bug 863808 - Implement a store buffer for marking whole objects. r=billm
authorTerrence Cole <terrence@mozilla.com>
Fri, 19 Apr 2013 13:38:25 -0700
changeset 142229 54986162d9bdcdfa0ffa7ca91da3c5ad8f2ba71b
parent 142228 7003849feda0e37fb39e89f41151d0210b749a28
child 142230 a15fae0ee76e12b78862b98eb256da2c2d1d9901
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs863808
milestone23.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 863808 - Implement a store buffer for marking whole objects. r=billm
js/src/gc/StoreBuffer.cpp
js/src/gc/StoreBuffer.h
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -51,16 +51,22 @@ StoreBuffer::SlotEdge::inRememberedSet(N
 }
 
 JS_ALWAYS_INLINE bool
 StoreBuffer::SlotEdge::isNullEdge() const
 {
     return !deref();
 }
 
+void
+StoreBuffer::WholeObjectEdges::mark(JSTracer *trc)
+{
+    tenured->markChildren(trc);
+}
+
 /*** MonoTypeBuffer ***/
 
 
 /* How full we allow a store buffer to become before we request a MinorGC. */
 const static double HighwaterRatio = 7.0 / 8.0;
 
 template <typename T>
 bool
@@ -162,16 +168,49 @@ StoreBuffer::MonoTypeBuffer<T>::accumula
         if (edge.isNullEdge())
             continue;
         if (!edges.putNew(edge.location()))
             return false;
     }
     return true;
 }
 
+namespace js {
+namespace gc {
+class AccumulateEdgesTracer : public JSTracer
+{
+    EdgeSet *edges;
+
+    static void tracer(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) {
+        AccumulateEdgesTracer *trc = static_cast<AccumulateEdgesTracer *>(jstrc);
+        trc->edges->put(thingp);
+    }
+
+  public:
+    AccumulateEdgesTracer(JSRuntime *rt, EdgeSet *edgesArg) : edges(edgesArg) {
+        JS_TracerInit(this, rt, AccumulateEdgesTracer::tracer);
+    }
+};
+
+template <>
+bool
+StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeObjectEdges>::accumulateEdges(EdgeSet &edges)
+{
+    compact();
+    AccumulateEdgesTracer trc(owner->runtime, &edges);
+    StoreBuffer::WholeObjectEdges *cursor = base;
+    while (cursor != pos) {
+        cursor->tenured->markChildren(&trc);
+        cursor++;
+    }
+    return true;
+}
+} /* namespace gc */
+} /* namespace js */
+
 /*** RelocatableMonoTypeBuffer ***/
 
 template <typename T>
 void
 StoreBuffer::RelocatableMonoTypeBuffer<T>::compactMoved()
 {
     for (T *v = this->base; v != this->pos; ++v) {
         if (v->isTagged()) {
@@ -303,16 +342,20 @@ StoreBuffer::enable()
     if (!bufferCell.enable(&asBytes[offset], CellBufferSize))
         return false;
     offset += CellBufferSize;
 
     if (!bufferSlot.enable(&asBytes[offset], SlotBufferSize))
         return false;
     offset += SlotBufferSize;
 
+    if (!bufferWholeObject.enable(&asBytes[offset], WholeObjectBufferSize))
+        return false;
+    offset += WholeObjectBufferSize;
+
     if (!bufferRelocVal.enable(&asBytes[offset], RelocValueBufferSize))
         return false;
     offset += RelocValueBufferSize;
 
     if (!bufferRelocCell.enable(&asBytes[offset], RelocCellBufferSize))
         return false;
     offset += RelocCellBufferSize;
 
@@ -332,16 +375,17 @@ StoreBuffer::disable()
     if (!enabled)
         return;
 
     aboutToOverflow = false;
 
     bufferVal.disable();
     bufferCell.disable();
     bufferSlot.disable();
+    bufferWholeObject.disable();
     bufferRelocVal.disable();
     bufferRelocCell.disable();
     bufferGeneric.disable();
 
     js_free(buffer);
     enabled = false;
     overflowed = false;
 }
@@ -352,32 +396,34 @@ StoreBuffer::clear()
     if (!enabled)
         return true;
 
     aboutToOverflow = false;
 
     bufferVal.clear();
     bufferCell.clear();
     bufferSlot.clear();
+    bufferWholeObject.clear();
     bufferRelocVal.clear();
     bufferRelocCell.clear();
     bufferGeneric.clear();
 
     return true;
 }
 
 void
 StoreBuffer::mark(JSTracer *trc)
 {
     JS_ASSERT(isEnabled());
     JS_ASSERT(!overflowed);
 
     bufferVal.mark(trc);
     bufferCell.mark(trc);
     bufferSlot.mark(trc);
+    bufferWholeObject.mark(trc);
     bufferRelocVal.mark(trc);
     bufferRelocCell.mark(trc);
     bufferGeneric.mark(trc);
 }
 
 void
 StoreBuffer::setAboutToOverflow()
 {
@@ -401,16 +447,18 @@ StoreBuffer::coalesceForVerification()
     }
     JS_ASSERT(edgeSet.empty());
     if (!bufferVal.accumulateEdges(edgeSet))
         return false;
     if (!bufferCell.accumulateEdges(edgeSet))
         return false;
     if (!bufferSlot.accumulateEdges(edgeSet))
         return false;
+    if (!bufferWholeObject.accumulateEdges(edgeSet))
+        return false;
     if (!bufferRelocVal.accumulateEdges(edgeSet))
         return false;
     if (!bufferRelocCell.accumulateEdges(edgeSet))
         return false;
     return true;
 }
 
 bool
@@ -423,12 +471,13 @@ void
 StoreBuffer::releaseVerificationData()
 {
     edgeSet.finish();
 }
 
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotEdge>;
+template class StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeObjectEdges>;
 template class StoreBuffer::RelocatableMonoTypeBuffer<StoreBuffer::ValueEdge>;
 template class StoreBuffer::RelocatableMonoTypeBuffer<StoreBuffer::CellPtrEdge>;
 
 #endif /* JSGC_GENERATIONAL */
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -14,16 +14,18 @@
 
 #include "jsgc.h"
 #include "jsalloc.h"
 #include "jsobj.h"
 
 namespace js {
 namespace gc {
 
+class AccumulateEdgesTracer;
+
 #ifdef JS_GC_ZEAL
 /*
  * Note: this is a stub Nursery that does not actually contain a heap, just a
  * set of pointers which are "inside" the nursery to implement verification.
  */
 class VerifierNursery
 {
     HashSet<const void *, PointerHasher<const void *, 3>, SystemAllocPolicy> nursery;
@@ -108,24 +110,24 @@ class HashKeyRef : public BufferableRef
         Mark(trc, &key, "HashKeyRef");
         if (prior != key) {
             map->remove(prior);
             map->put(key, value);
         }
     }
 };
 
+typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> EdgeSet;
+
 /*
  * The StoreBuffer observes all writes that occur in the system and performs
  * efficient filtering of them to derive a remembered set for nursery GC.
  */
 class StoreBuffer
 {
-    typedef HashSet<void *, PointerHasher<void *, 3>, SystemAllocPolicy> EdgeSet;
-
     /*
      * This buffer holds only a single type of edge. Using this buffer is more
      * efficient than the generic buffer when many writes will be to the same
      * type of edge: e.g. Value or Cell*.
      */
     template<typename T>
     class MonoTypeBuffer
     {
@@ -369,62 +371,80 @@ class StoreBuffer
         template <typename NurseryType>
         JS_ALWAYS_INLINE bool inRememberedSet(NurseryType *nursery) const;
 
         JS_ALWAYS_INLINE bool isNullEdge() const;
 
         void mark(JSTracer *trc);
     };
 
+    class WholeObjectEdges
+    {
+        friend class StoreBuffer;
+        friend class StoreBuffer::MonoTypeBuffer<WholeObjectEdges>;
+
+        JSObject *tenured;
+
+        WholeObjectEdges(JSObject *obj) : tenured(obj) {
+            JS_ASSERT(tenured->isTenured());
+        }
+
+        bool operator==(const WholeObjectEdges &other) const { return tenured == other.tenured; }
+        bool operator!=(const WholeObjectEdges &other) const { return tenured != other.tenured; }
+
+        template <typename NurseryType>
+        bool inRememberedSet(NurseryType *nursery) const { return true; }
+
+        /* This is used by RemoveDuplicates as a unique pointer to this Edge. */
+        void *location() const { return (void *)tenured; }
+
+        bool isNullEdge() const { return false; }
+
+        void mark(JSTracer *trc);
+    };
+
     MonoTypeBuffer<ValueEdge> bufferVal;
     MonoTypeBuffer<CellPtrEdge> bufferCell;
     MonoTypeBuffer<SlotEdge> bufferSlot;
+    MonoTypeBuffer<WholeObjectEdges> bufferWholeObject;
     RelocatableMonoTypeBuffer<ValueEdge> bufferRelocVal;
     RelocatableMonoTypeBuffer<CellPtrEdge> bufferRelocCell;
     GenericBuffer bufferGeneric;
 
     JSRuntime *runtime;
 
     void *buffer;
 
     bool aboutToOverflow;
     bool overflowed;
     bool enabled;
 
     /* For the verifier. */
     EdgeSet edgeSet;
 
-#ifdef JS_GC_ZEAL
-    /* For verification, we approximate an infinitly large buffer. */
-    static const size_t ValueBufferSize = 1024 * 1024 * sizeof(ValueEdge);
-    static const size_t CellBufferSize = 1024 * 1024 * sizeof(CellPtrEdge);
-    static const size_t SlotBufferSize = 1024 * 1024 * sizeof(SlotEdge);
-    static const size_t RelocValueBufferSize = 1 * 1024 * sizeof(ValueEdge);
-    static const size_t RelocCellBufferSize = 1 * 1024 * sizeof(CellPtrEdge);
-    static const size_t GenericBufferSize = 1024 * 1024 * sizeof(int);
-#else
     /* TODO: profile to find the ideal size for these. */
     static const size_t ValueBufferSize = 1 * 1024 * sizeof(ValueEdge);
     static const size_t CellBufferSize = 2 * 1024 * sizeof(CellPtrEdge);
     static const size_t SlotBufferSize = 2 * 1024 * sizeof(SlotEdge);
+    static const size_t WholeObjectBufferSize = 2 * 1024 * sizeof(WholeObjectEdges);
     static const size_t RelocValueBufferSize = 1 * 1024 * sizeof(ValueEdge);
     static const size_t RelocCellBufferSize = 1 * 1024 * sizeof(CellPtrEdge);
     static const size_t GenericBufferSize = 1 * 1024 * sizeof(int);
-#endif
     static const size_t TotalSize = ValueBufferSize + CellBufferSize +
-                                    SlotBufferSize + RelocValueBufferSize + RelocCellBufferSize +
+                                    SlotBufferSize + WholeObjectBufferSize +
+                                    RelocValueBufferSize + RelocCellBufferSize +
                                     GenericBufferSize;
 
     /* For use by our owned buffers. */
     void setAboutToOverflow();
     void setOverflowed();
 
   public:
     explicit StoreBuffer(JSRuntime *rt)
-      : bufferVal(this), bufferCell(this), bufferSlot(this),
+      : bufferVal(this), bufferCell(this), bufferSlot(this), bufferWholeObject(this),
         bufferRelocVal(this), bufferRelocCell(this), bufferGeneric(this),
         runtime(rt), buffer(NULL), aboutToOverflow(false), overflowed(false),
         enabled(false)
     {}
 
     bool enable();
     void disable();
     bool isEnabled() { return enabled; }
@@ -440,16 +460,19 @@ class StoreBuffer
         bufferVal.put(v);
     }
     void putCell(Cell **o) {
         bufferCell.put(o);
     }
     void putSlot(JSObject *obj, HeapSlot::Kind kind, uint32_t slot) {
         bufferSlot.put(SlotEdge(obj, kind, slot));
     }
+    void putWholeObject(JSObject *obj) {
+        bufferWholeObject.put(WholeObjectEdges(obj));
+    }
 
     /* Insert or update a single edge in the Relocatable buffer. */
     void putRelocatableValue(Value *v) {
         bufferRelocVal.put(v);
     }
     void putRelocatableCell(Cell **c) {
         bufferRelocCell.put(c);
     }