Bug 1263771 - Sweep the InnerViewTable with WeakCache; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Mon, 21 Dec 2015 16:20:42 -0800
changeset 293324 ab87b53b3140fbb5e9e2caa5325ae0d791ee43d4
parent 293323 b23a6286c125783b582eb59967ab5e574133478a
child 293325 86bd74d49e63a7f6a5445a1f6d254689ad9accd0
push id18749
push usercbook@mozilla.com
push dateFri, 15 Apr 2016 12:01:19 +0000
treeherderfx-team@8f7045b63b07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1263771
milestone48.0a1
Bug 1263771 - Sweep the InnerViewTable with WeakCache; r=sfink
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsgc.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -63,16 +63,17 @@ JSCompartment::JSCompartment(Zone* zone,
     lastAnimationTime(0),
     regExps(runtime_),
     globalWriteBarriered(false),
     detachedTypedObjects(0),
     objectMetadataState(ImmediateMetadata()),
     propertyTree(thisForCtor()),
     selfHostingScriptSource(nullptr),
     objectMetadataTable(nullptr),
+    innerViews(zone, InnerViewTable()),
     lazyArrayBuffers(nullptr),
     nonSyntacticLexicalScopes_(nullptr),
     gcIncomingGrayPointers(nullptr),
     debugModeBits(0),
     watchpointMap(nullptr),
     scriptCountsMap(nullptr),
     debugScriptMap(nullptr),
     debugScopes(nullptr),
@@ -660,22 +661,16 @@ JSCompartment::sweepAfterMinorGC()
 {
     globalWriteBarriered = false;
 
     if (innerViews.needsSweepAfterMinorGC())
         innerViews.sweepAfterMinorGC();
 }
 
 void
-JSCompartment::sweepInnerViews()
-{
-    innerViews.sweep();
-}
-
-void
 JSCompartment::sweepSavedStacks()
 {
     savedStacks_.sweep();
 }
 
 void
 JSCompartment::sweepGlobalObject(FreeOp* fop)
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -461,17 +461,17 @@ struct JSCompartment
      */
     js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
 
     // Keep track of the metadata objects which can be associated with each JS
     // object. Both keys and values are in this compartment.
     js::ObjectWeakMap* objectMetadataTable;
 
     // Map from array buffers to views sharing that storage.
-    js::InnerViewTable innerViews;
+    JS::WeakCache<js::InnerViewTable> innerViews;
 
     // Inline transparent typed objects do not initially have an array buffer,
     // but can have that buffer created lazily if it is accessed later. This
     // table manages references from such typed objects to their buffers.
     js::ObjectWeakMap* lazyArrayBuffers;
 
     // All unboxed layouts in the compartment.
     mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
@@ -581,17 +581,16 @@ struct JSCompartment
     void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
     static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
 
     /* Whether to preserve JIT code on non-shrinking GCs. */
     bool preserveJitCode() { return creationOptions_.preserveJitCode(); }
 
     void sweepAfterMinorGC();
 
-    void sweepInnerViews();
     void sweepCrossCompartmentWrappers();
     void sweepSavedStacks();
     void sweepGlobalObject(js::FreeOp* fop);
     void sweepObjectPendingMetadata();
     void sweepSelfHostingScriptSource();
     void sweepJitCompartment(js::FreeOp* fop);
     void sweepRegExps();
     void sweepDebugScopes();
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2447,17 +2447,16 @@ GCRuntime::sweepZoneAfterCompacting(Zone
     FreeOp* fop = rt->defaultFreeOp();
     sweepTypesAfterCompacting(zone);
     zone->sweepBreakpoints(fop);
     zone->sweepWeakMaps();
     for (auto* cache : zone->weakCaches_)
         cache->sweep();
 
     for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
-        c->sweepInnerViews();
         c->sweepBaseShapeTable();
         c->sweepInitialShapeTable();
         c->objectGroups.sweep(fop);
         c->sweepRegExps();
         c->sweepSavedStacks();
         c->sweepGlobalObject(fop);
         c->sweepObjectPendingMetadata();
         c->sweepSelfHostingScriptSource();
@@ -5058,39 +5057,31 @@ class SweepWeakCacheTask : public GCSwee
 
 #define MAKE_GC_SWEEP_TASK(name)                                              \
     class name : public GCSweepTask {                                         \
         void run() override;                                          \
       public:                                                                 \
         explicit name (JSRuntime* rt) : GCSweepTask(rt) {}                    \
     }
 MAKE_GC_SWEEP_TASK(SweepAtomsTask);
-MAKE_GC_SWEEP_TASK(SweepInnerViewsTask);
 MAKE_GC_SWEEP_TASK(SweepCCWrappersTask);
 MAKE_GC_SWEEP_TASK(SweepBaseShapesTask);
 MAKE_GC_SWEEP_TASK(SweepInitialShapesTask);
 MAKE_GC_SWEEP_TASK(SweepObjectGroupsTask);
 MAKE_GC_SWEEP_TASK(SweepRegExpsTask);
 MAKE_GC_SWEEP_TASK(SweepMiscTask);
 #undef MAKE_GC_SWEEP_TASK
 
 /* virtual */ void
 SweepAtomsTask::run()
 {
     runtime->sweepAtoms();
 }
 
 /* virtual */ void
-SweepInnerViewsTask::run()
-{
-    for (GCCompartmentGroupIter c(runtime); !c.done(); c.next())
-        c->sweepInnerViews();
-}
-
-/* virtual */ void
 SweepCCWrappersTask::run()
 {
     for (GCCompartmentGroupIter c(runtime); !c.done(); c.next())
         c->sweepCrossCompartmentWrappers();
 }
 
 /* virtual */ void
 SweepBaseShapesTask::run()
@@ -5175,17 +5166,16 @@ GCRuntime::beginSweepingZoneGroup()
         zone->gcLastZoneGroupIndex = zoneGroupIndex;
 #endif
     }
 
     validateIncrementalMarking();
 
     FreeOp fop(rt);
     SweepAtomsTask sweepAtomsTask(rt);
-    SweepInnerViewsTask sweepInnerViewsTask(rt);
     SweepCCWrappersTask sweepCCWrappersTask(rt);
     SweepBaseShapesTask sweepBaseShapesTask(rt);
     SweepInitialShapesTask sweepInitialShapesTask(rt);
     SweepObjectGroupsTask sweepObjectGroupsTask(rt);
     SweepRegExpsTask sweepRegExpsTask(rt);
     SweepMiscTask sweepMiscTask(rt);
     mozilla::Vector<SweepWeakCacheTask> sweepCacheTasks;
 
@@ -5231,17 +5221,16 @@ GCRuntime::beginSweepingZoneGroup()
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
         gcstats::AutoSCC scc(stats, zoneGroupIndex);
 
         {
             AutoLockHelperThreadState helperLock;
-            startTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS);
             startTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER);
             startTask(sweepBaseShapesTask, gcstats::PHASE_SWEEP_BASE_SHAPE);
             startTask(sweepInitialShapesTask, gcstats::PHASE_SWEEP_INITIAL_SHAPE);
             startTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT);
             startTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP);
             startTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC);
             for (auto& task : sweepCacheTasks)
                 startTask(task, gcstats::PHASE_SWEEP_MISC);
@@ -5314,17 +5303,16 @@ GCRuntime::beginSweepingZoneGroup()
         joinTask(sweepAtomsTask, gcstats::PHASE_SWEEP_ATOMS);
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
         gcstats::AutoSCC scc(stats, zoneGroupIndex);
 
         AutoLockHelperThreadState helperLock;
-        joinTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS);
         joinTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER);
         joinTask(sweepBaseShapesTask, gcstats::PHASE_SWEEP_BASE_SHAPE);
         joinTask(sweepInitialShapesTask, gcstats::PHASE_SWEEP_INITIAL_SHAPE);
         joinTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT);
         joinTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP);
         joinTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC);
         for (auto& task : sweepCacheTasks)
             joinTask(task, gcstats::PHASE_SWEEP_MISC);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -287,20 +287,21 @@ ArrayBufferObject::detach(JSContext* cx,
             oomUnsafe.crash("ArrayBufferObject::detach");
         MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER);
         cx->compartment()->detachedTypedObjects = 1;
     }
 
     // Update all views of the buffer to account for the buffer having been
     // detached, and clear the buffer's data and list of views.
 
-    if (InnerViewTable::ViewVector* views = cx->compartment()->innerViews.maybeViewsUnbarriered(buffer)) {
+    auto& innerViews = cx->compartment()->innerViews;
+    if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(buffer)) {
         for (size_t i = 0; i < views->length(); i++)
             NoteViewBufferWasDetached((*views)[i], newContents, cx);
-        cx->compartment()->innerViews.removeViews(buffer);
+        innerViews.removeViews(buffer);
     }
     if (buffer->firstView()) {
         if (buffer->forInlineTypedObject()) {
             // The buffer points to inline data in its first view, so to keep
             // this pointer alive we don't clear out the first view.
             MOZ_ASSERT(buffer->firstView()->is<InlineTransparentTypedObject>());
         } else {
             NoteViewBufferWasDetached(buffer->firstView(), newContents, cx);
@@ -359,17 +360,18 @@ ArrayBufferObject::changeContents(JSCont
 {
     MOZ_ASSERT(!forInlineTypedObject());
 
     // Change buffer contents.
     uint8_t* oldDataPointer = dataPointer();
     setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);
 
     // Update all views.
-    if (InnerViewTable::ViewVector* views = cx->compartment()->innerViews.maybeViewsUnbarriered(this)) {
+    auto& innerViews = cx->compartment()->innerViews;
+    if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
         for (size_t i = 0; i < views->length(); i++)
             changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
     }
     if (firstView())
         changeViewContents(cx, firstView(), oldDataPointer, newContents);
 }
 
 #ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
@@ -850,17 +852,17 @@ ArrayBufferObject::addView(JSContext* cx
     // inherit from ArrayBufferViewObject so won't be upcast automatically.
     MOZ_ASSERT(viewArg->is<ArrayBufferViewObject>() || viewArg->is<TypedObject>());
     ArrayBufferViewObject* view = static_cast<ArrayBufferViewObject*>(viewArg);
 
     if (!firstView()) {
         setFirstView(view);
         return true;
     }
-    return cx->compartment()->innerViews.addView(cx, this, view);
+    return cx->compartment()->innerViews.get().addView(cx, this, view);
 }
 
 /*
  * InnerViewTable
  */
 
 static size_t VIEW_LIST_MAX_LENGTH = 500;
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -495,16 +495,17 @@ template<> inline bool TypeIsUnsigned<ui
 // Per-compartment table that manages the relationship between array buffers
 // and the views that use their storage.
 class InnerViewTable
 {
   public:
     typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
 
     friend class ArrayBufferObject;
+    friend class WeakCacheBase<InnerViewTable>;
 
   private:
     struct MapGCPolicy {
         static bool needsSweep(JSObject** key, ViewVector* value) {
             return InnerViewTable::sweepEntry(key, *value);
         }
     };
 
@@ -548,23 +549,45 @@ class InnerViewTable
       : nurseryKeysValid(true)
     {}
 
     // Remove references to dead objects in the table and update table entries
     // to reflect moved objects.
     void sweep();
     void sweepAfterMinorGC();
 
-    bool needsSweepAfterMinorGC() {
+    bool needsSweepAfterMinorGC() const {
         return !nurseryKeys.empty() || !nurseryKeysValid;
     }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
+template <>
+class WeakCacheBase<InnerViewTable>
+{
+    InnerViewTable& table() {
+        return static_cast<JS::WeakCache<InnerViewTable>*>(this)->get();
+    }
+    const InnerViewTable& table() const {
+        return static_cast<const JS::WeakCache<InnerViewTable>*>(this)->get();
+    }
+
+  public:
+    InnerViewTable::ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj) {
+        return table().maybeViewsUnbarriered(obj);
+    }
+    void removeViews(ArrayBufferObject* obj) { table().removeViews(obj); }
+    void sweepAfterMinorGC() { table().sweepAfterMinorGC(); }
+    bool needsSweepAfterMinorGC() const { return table().needsSweepAfterMinorGC(); }
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
+        return table().sizeOfExcludingThis(mallocSizeOf);
+    }
+};
+
 extern JSObject*
 InitArrayBufferClass(JSContext* cx, HandleObject obj);
 
 } // namespace js
 
 template <>
 bool
 JSObject::is<js::ArrayBufferViewObject>() const;