Bug 1133759 - Always shrink GC buffers at the end of a shrinking GC r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 18 Feb 2015 12:35:05 +0000
changeset 229687 45a72ac5b38234163e36eacd18c4a2ec4a4e429d
parent 229686 2f68cea9b4c963e7ab101ce96778915bb0f39014
child 229688 ddf7147e8a2f7f6d3736407c59936e762af5b106
push id28294
push userryanvm@gmail.com
push dateThu, 19 Feb 2015 01:30:38 +0000
treeherdermozilla-central@360b5f211180 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1133759
milestone38.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 1133759 - Always shrink GC buffers at the end of a shrinking GC r=terrence
dom/base/nsJSEnvironment.cpp
js/public/GCAPI.h
js/src/gc/Statistics.cpp
js/src/jsgc.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2199,18 +2199,21 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::G
                                              nullptr,
                                              NS_FULL_GC_DELAY,
                                              nsITimer::TYPE_ONE_SHOT);
         }
       } else {
         nsJSContext::KillFullGCTimer();
 
         // Avoid shrinking during heavy activity, which is suggested by
-        // compartment GC.
-        nsJSContext::PokeShrinkGCBuffers();
+        // compartment GC. We don't need to shrink after a shrinking GC as this
+        // happens automatically in this case.
+        if (aDesc.invocationKind_ == GC_NORMAL) {
+          nsJSContext::PokeShrinkGCBuffers();
+        }
       }
 
       if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
         nsCycleCollector_dispatchDeferredDeletion();
       }
 
       break;
     }
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -258,19 +258,20 @@ enum GCProgress {
     GC_CYCLE_BEGIN,
     GC_SLICE_BEGIN,
     GC_SLICE_END,
     GC_CYCLE_END
 };
 
 struct JS_PUBLIC_API(GCDescription) {
     bool isCompartment_;
+    JSGCInvocationKind invocationKind_;
 
-    explicit GCDescription(bool isCompartment)
-      : isCompartment_(isCompartment) {}
+    GCDescription(bool isCompartment, JSGCInvocationKind kind)
+      : isCompartment_(isCompartment), invocationKind_(kind) {}
 
     char16_t *formatMessage(JSRuntime *rt) const;
     char16_t *formatJSON(JSRuntime *rt, uint64_t timestamp) const;
 };
 
 typedef void
 (* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc);
 
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -1000,17 +1000,17 @@ Statistics::beginSlice(const ZoneGCStats
 
     runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
 
     // Slice callbacks should only fire for the outermost level
     if (++gcDepth == 1) {
         bool wasFullGC = zoneStats.isCollectingAllZones();
         if (sliceCallback)
             (*sliceCallback)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN,
-                             JS::GCDescription(!wasFullGC));
+                             JS::GCDescription(!wasFullGC, gckind));
     }
 }
 
 void
 Statistics::endSlice()
 {
     if (!aborted) {
         slices.back().end = PRMJ_Now();
@@ -1024,17 +1024,17 @@ Statistics::endSlice()
     if (last)
         endGC();
 
     // Slice callbacks should only fire for the outermost level
     if (--gcDepth == 0) {
         bool wasFullGC = zoneStats.isCollectingAllZones();
         if (sliceCallback)
             (*sliceCallback)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END,
-                             JS::GCDescription(!wasFullGC));
+                             JS::GCDescription(!wasFullGC, gckind));
     }
 
     /* Do this after the slice callback since it uses these values. */
     if (last)
         PodArrayZero(counts);
 }
 
 void
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -5458,16 +5458,20 @@ GCRuntime::compactPhase(bool lastGC)
     protectRelocatedArenas(relocatedList);
     MOZ_ASSERT(!relocatedArenasToRelease);
     if (!lastGC)
         relocatedArenasToRelease = relocatedList;
     else
         releaseRelocatedArenas(relocatedList);
 #endif
 
+    // Ensure execess chunks are returns to the system and free arenas
+    // decommitted.
+    shrinkBuffers();
+
 #ifdef DEBUG
     CheckHashTablesAfterMovingGC(rt);
     for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
         if (CanRelocateZone(rt, zone)) {
             MOZ_ASSERT(!zone->isPreservingCode());
             zone->arenas.checkEmptyFreeLists();
 
             // Check that we did as much compaction as we should have. There
@@ -6298,25 +6302,25 @@ js::PrepareForDebugGC(JSRuntime *rt)
 {
     if (!ZonesSelected(rt))
         JS::PrepareForFullGC(rt);
 }
 
 JS_PUBLIC_API(void)
 JS::ShrinkGCBuffers(JSRuntime *rt)
 {
+    MOZ_ASSERT(!rt->isHeapBusy());
     rt->gc.shrinkBuffers();
 }
 
 void
 GCRuntime::shrinkBuffers()
 {
     AutoLockHelperThreadState helperLock;
     AutoLockGC lock(rt);
-    MOZ_ASSERT(!rt->isHeapBusy());
 
     if (CanUseExtraThreads())
         helperState.startBackgroundShrink(lock);
     else
         expireChunksAndArenas(true, lock);
 }
 
 void