Bug 1396936 - Simplify tenuring of objects with unique IDs and remove hash table lookup for every tenured object r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 06 Sep 2017 09:07:10 +0100
changeset 379297 6c55a6e0ff0f1f2a0b07ab9dc80ac38cc3624ca9
parent 379296 8d1a2ad4d81160488a7ec54cb0ed3abfa369ba77
child 379298 f719e2cf81ea792377ccaaf5ef2635b3a24aada8
push id32453
push userarchaeopteryx@coole-files.de
push dateThu, 07 Sep 2017 10:39:44 +0000
treeherdermozilla-central@37b95547f0d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1396936
milestone57.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 1396936 - Simplify tenuring of objects with unique IDs and remove hash table lookup for every tenured object r=sfink
js/src/gc/Marking.cpp
js/src/gc/Nursery.cpp
js/src/gc/Nursery.h
js/src/gc/Zone.h
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2960,19 +2960,16 @@ js::TenuringTracer::moveObjectToTenured(
             srcSize = headerSize + tarray->byteLength();
         }
     }
 
     // Copy the Cell contents.
     MOZ_ASSERT(OffsetToChunkEnd(src) >= ptrdiff_t(srcSize));
     js_memcpy(dst, src, srcSize);
 
-    // Move any hash code attached to the object.
-    src->zone()->transferUniqueId(dst, src);
-
     // Move the slots and elements, if we need to.
     if (src->isNative()) {
         NativeObject* ndst = &dst->as<NativeObject>();
         NativeObject* nsrc = &src->as<NativeObject>();
         tenuredSize += moveSlotsToTenured(ndst, nsrc, dstKind);
         tenuredSize += moveElementsToTenured(ndst, nsrc, dstKind);
 
         // There is a pointer into a dictionary mode object from the head of its
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -774,40 +774,40 @@ js::Nursery::doCollection(JS::gcreason::
     // Most of the work is done here. This loop iterates over objects that have
     // been moved to the major heap. If these objects have any outgoing pointers
     // to the nursery, then those nursery objects get moved as well, until no
     // objects are left to move. That is, we iterate to a fixed point.
     startProfile(ProfileKey::CollectToFP);
     collectToFixedPoint(mover, tenureCounts);
     endProfile(ProfileKey::CollectToFP);
 
-    // Sweep compartments to update the array buffer object's view lists.
-    startProfile(ProfileKey::SweepArrayBufferViewList);
-    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
-        c->sweepAfterMinorGC(&mover);
-    endProfile(ProfileKey::SweepArrayBufferViewList);
+    // Sweep to update any pointers to nursery objects that have now been
+    // tenured.
+    startProfile(ProfileKey::Sweep);
+    sweep(&mover);
+    endProfile(ProfileKey::Sweep);
 
     // Update any slot or element pointers whose destination has been tenured.
     startProfile(ProfileKey::UpdateJitActivations);
     js::jit::UpdateJitActivationsForMinorGC(rt, &mover);
     forwardedBuffers.finish();
     endProfile(ProfileKey::UpdateJitActivations);
 
     startProfile(ProfileKey::ObjectsTenuredCallback);
     rt->gc.callObjectsTenuredCallback();
     endProfile(ProfileKey::ObjectsTenuredCallback);
 
     // Sweep.
     startProfile(ProfileKey::FreeMallocedBuffers);
     freeMallocedBuffers();
     endProfile(ProfileKey::FreeMallocedBuffers);
 
-    startProfile(ProfileKey::Sweep);
-    sweep();
-    endProfile(ProfileKey::Sweep);
+    startProfile(ProfileKey::ClearNursery);
+    clear();
+    endProfile(ProfileKey::ClearNursery);
 
     startProfile(ProfileKey::ClearStoreBuffer);
     runtime()->gc.storeBuffer().clear();
     endProfile(ProfileKey::ClearStoreBuffer);
 
     // Make sure hashtables have been updated after the collection.
     startProfile(ProfileKey::CheckHashTables);
 #ifdef JS_GC_ZEAL
@@ -868,30 +868,40 @@ js::Nursery::waitBackgroundFreeEnd()
     if (!isEnabled())
         return;
 
     MOZ_ASSERT(freeMallocedBuffersTask);
     freeMallocedBuffersTask->join();
 }
 
 void
-js::Nursery::sweep()
+js::Nursery::sweep(JSTracer* trc)
 {
-    /* Sweep unique id's in all in-use chunks. */
+    // Sweep unique IDs first before we sweep any tables that may be keyed based
+    // on them.
     for (Cell* cell : cellsWithUid_) {
         JSObject* obj = static_cast<JSObject*>(cell);
-        if (!IsForwarded(obj))
+        if (!IsForwarded(obj)) {
             obj->zone()->removeUniqueId(obj);
-        else
-            MOZ_ASSERT(Forwarded(obj)->zone()->hasUniqueId(Forwarded(obj)));
+        } else {
+            JSObject* dst = Forwarded(obj);
+            dst->zone()->transferUniqueId(dst, obj);
+        }
     }
     cellsWithUid_.clear();
 
+    for (CompartmentsIter c(runtime(), SkipAtoms); !c.done(); c.next())
+        c->sweepAfterMinorGC(trc);
+
     sweepDictionaryModeObjects();
+}
 
+void
+js::Nursery::clear()
+{
 #ifdef JS_GC_ZEAL
     /* Poison the nursery contents so touching a freed object will crash. */
     for (unsigned i = 0; i < numChunks(); i++)
         chunk(i).poisonAndInit(runtime(), JS_SWEPT_NURSERY_PATTERN);
 
     if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
         /* Only reset the alloc point when we are close to the end. */
         if (currentChunk_ + 1 == numChunks())
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -35,21 +35,21 @@
     _(TraceWholeCells,          "mcWCll")                                     \
     _(TraceGenericEntries,      "mkGnrc")                                     \
     _(CheckHashTables,          "ckTbls")                                     \
     _(MarkRuntime,              "mkRntm")                                     \
     _(MarkDebugger,             "mkDbgr")                                     \
     _(ClearNewObjectCache,      "clrNOC")                                     \
     _(CollectToFP,              "collct")                                     \
     _(ObjectsTenuredCallback,   "tenCB")                                      \
-    _(SweepArrayBufferViewList, "swpABO")                                     \
+    _(Sweep,                    "sweep")                                      \
     _(UpdateJitActivations,     "updtIn")                                     \
     _(FreeMallocedBuffers,      "frSlts")                                     \
     _(ClearStoreBuffer,         "clrSB")                                      \
-    _(Sweep,                    "sweep")                                      \
+    _(ClearNursery,             "clear")                                      \
     _(Resize,                   "resize")                                     \
     _(Pretenure,                "pretnr")
 
 namespace JS {
 struct Zone;
 } // namespace JS
 
 namespace js {
@@ -469,20 +469,26 @@ class Nursery
     void setSlotsForwardingPointer(HeapSlot* oldSlots, HeapSlot* newSlots, uint32_t nslots);
     void setElementsForwardingPointer(ObjectElements* oldHeader, ObjectElements* newHeader,
                                       uint32_t capacity);
 
     /* Free malloced pointers owned by freed things in the nursery. */
     void freeMallocedBuffers();
 
     /*
+     * Updates pointers to nursery objects that have been tenured and discards
+     * pointers to objects that have been freed.
+     */
+    void sweep(JSTracer* trc);
+
+    /*
      * Frees all non-live nursery-allocated things at the end of a minor
      * collection.
      */
-    void sweep();
+    void clear();
 
     void sweepDictionaryModeObjects();
 
     /* Change the allocable space provided by the nursery. */
     void maybeResizeNursery(JS::gcreason::Reason reason);
     void growAllocableSpace();
     void shrinkAllocableSpace(unsigned removeNumChunks);
     void minimizeAllocableSpace();
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -617,16 +617,17 @@ struct Zone : public JS::shadow::Zone,
 
     // Transfer an id from another cell. This must only be called on behalf of a
     // moving GC. This method is infallible.
     void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src) {
         MOZ_ASSERT(src != tgt);
         MOZ_ASSERT(!IsInsideNursery(tgt));
         MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromActiveCooperatingThread()));
         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
+        MOZ_ASSERT(!uniqueIds().has(tgt));
         uniqueIds().rekeyIfMoved(src, tgt);
     }
 
     // Remove any unique id associated with this Cell.
     void removeUniqueId(js::gc::Cell* cell) {
         MOZ_ASSERT(js::CurrentThreadCanAccessZone(this));
         uniqueIds().remove(cell);
     }