Bug 1259306 - Trace ShapeTables r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 30 Mar 2016 12:33:55 +0100
changeset 291056 457e7d5b11363cf859bb4c476701cf4803f452c4
parent 291055 dbbe7c7e305daafc0bb6533a4e39a64a3bc6b38f
child 291057 24b56ce6d8db255d1fbf691753ab07f99c07b3c5
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1259306
milestone48.0a1
Bug 1259306 - Trace ShapeTables r=terrence * * * Bug 1259306 - Don't report BaseShapes to cycle collector
js/src/gc/Tracer.cpp
js/src/jspropertytree.cpp
js/src/vm/Shape.cpp
js/src/vm/Shape.h
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -220,20 +220,16 @@ gc::TraceCycleCollectorChildren(JS::Call
             DoCallback(trc, &tmp, "setter");
             MOZ_ASSERT(tmp == shape->setterObject());
         }
 
         shape = shape->previous();
     } while (shape);
 }
 
-void
-TraceObjectGroupCycleCollectorChildrenCallback(JS::CallbackTracer* trc,
-                                               void** thingp, JS::TraceKind kind);
-
 // Object groups can point to other object groups via an UnboxedLayout or the
 // the original unboxed group link. There can potentially be deep or cyclic
 // chains of such groups to trace through without going through a thing that
 // participates in cycle collection. These need to be handled iteratively to
 // avoid blowing the stack when running the cycle collector's callback tracer.
 struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
 {
     explicit ObjectGroupCycleCollectorTracer(JS::CallbackTracer* innerTracer)
@@ -245,16 +241,22 @@ struct ObjectGroupCycleCollectorTracer :
 
     JS::CallbackTracer* innerTracer;
     Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
 };
 
 void
 ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing)
 {
+    if (thing.is<BaseShape>()) {
+        // The CC does not care about BaseShapes, and no additional GC things
+        // will be reached by following this edge.
+        return;
+    }
+
     if (thing.is<JSObject>() || thing.is<JSScript>()) {
         // Invoke the inner cycle collector callback on this child. It will not
         // recurse back into TraceChildren.
         innerTracer->onChild(thing);
         return;
     }
 
     if (thing.is<ObjectGroup>()) {
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -314,24 +314,16 @@ Shape::fixupAfterMovingGC()
 {
     if (inDictionary())
         fixupDictionaryShapeAfterMovingGC();
     else
         fixupShapeTreeAfterMovingGC();
 }
 
 void
-BaseShape::fixupAfterMovingGC()
-{
-    if (hasTable())
-        table().fixupAfterMovingGC();
-}
-
-
-void
 Shape::fixupGetterSetterForBarrier(JSTracer* trc)
 {
     if (!hasGetterValue() && !hasSetterValue())
         return;
 
     JSObject* priorGetter = asAccessorShape().getterObj;
     JSObject* priorSetter = asAccessorShape().setterObj;
     if (!priorGetter && !priorSetter)
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -324,23 +324,26 @@ ShapeTable::grow(ExclusiveContext* cx)
 
         cx->recoverFromOutOfMemory();
     }
 
     return true;
 }
 
 void
-ShapeTable::fixupAfterMovingGC()
+ShapeTable::trace(JSTracer* trc)
 {
     for (size_t i = 0; i < capacity(); i++) {
         Entry& entry = getEntry(i);
         Shape* shape = entry.shape();
-        if (shape && IsForwarded(shape))
-            entry.setPreservingCollision(Forwarded(shape));
+        if (shape) {
+            TraceManuallyBarrieredEdge(trc, &shape, "ShapeTable shape");
+            if (shape != entry.shape())
+                entry.setPreservingCollision(shape);
+        }
     }
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
 ShapeTable::checkAfterMovingGC()
 {
@@ -1335,16 +1338,19 @@ BaseShape::traceChildren(JSTracer* trc)
         compartment()->mark();
 
     if (isOwned())
         TraceEdge(trc, &unowned_, "base");
 
     JSObject* global = compartment()->unsafeUnbarrieredMaybeGlobal();
     if (global)
         TraceManuallyBarrieredEdge(trc, &global, "global");
+
+    if (hasTable())
+        table().trace(trc);
 }
 
 void
 JSCompartment::sweepBaseShapeTable()
 {
     baseShapes.sweep();
 }
 
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -223,17 +223,17 @@ class ShapeTable {
      * order to update the malloc counter on success.
      */
     bool init(ExclusiveContext* cx, Shape* lastProp);
     bool change(int log2Delta, ExclusiveContext* cx);
 
     template<MaybeAdding Adding>
     Entry& search(jsid id);
 
-    void fixupAfterMovingGC();
+    void trace(JSTracer* trc);
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkAfterMovingGC();
 #endif
 
   private:
     Entry& getEntry(uint32_t i) const {
         MOZ_ASSERT(i < capacity());
         return entries_[i];
@@ -450,17 +450,17 @@ class BaseShape : public gc::TenuredCell
 
     /* For JIT usage */
     static inline size_t offsetOfFlags() { return offsetof(BaseShape, flags); }
 
     static const JS::TraceKind TraceKind = JS::TraceKind::BaseShape;
 
     void traceChildren(JSTracer* trc);
 
-    void fixupAfterMovingGC();
+    void fixupAfterMovingGC() {}
 
   private:
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(BaseShape, clasp_) == offsetof(js::shadow::BaseShape, clasp_));
         static_assert(sizeof(BaseShape) % gc::CellSize == 0,
                       "Things inheriting from gc::Cell must have a size that's "
                       "a multiple of gc::CellSize");
     }