Bug 844313 - Call GC more likely when there are lots of Events to collect. r=mccr8, a=tef+
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Fri, 08 Mar 2013 09:47:06 -0500
changeset 118692 94927529a55fb8d0a28e59ff672183f424ecf896
parent 118691 bbf58761f059b585d6493882e05990dcd233f953
child 118693 ef5bc68481727c677d71046c28da71ed6d23a27b
push id534
push userryanvm@gmail.com
push dateFri, 08 Mar 2013 14:47:07 +0000
reviewersmccr8, tef
bugs844313
milestone18.0
Bug 844313 - Call GC more likely when there are lots of Events to collect. r=mccr8, a=tef+
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMTouchEvent.cpp
content/events/src/nsDOMTouchEvent.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -18,16 +18,17 @@
 #include "nsIPresShell.h"
 #include "nsIDocument.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "prmem.h"
 #include "nsGkAtoms.h"
 #include "nsMutationEvent.h"
 #include "nsContentUtils.h"
+#include "nsJSEnvironment.h"
 #include "nsIURI.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptError.h"
 #include "mozilla/Preferences.h"
 #include "nsJSUtils.h"
 #include "DictionaryHelpers.h"
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
@@ -72,16 +73,17 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aP
           ...
         }
      */
     mEvent = new nsEvent(false, 0);
     mEvent->time = PR_Now();
   }
 
   InitPresContextData(aPresContext);
+  nsJSContext::LikelyShortLivingObjectCreated();
 }
 
 void
 nsDOMEvent::InitPresContextData(nsPresContext* aPresContext)
 {
   mPresContext = aPresContext;
   // Get the explicit original target (if it's anonymous make it null)
   {
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -6,16 +6,17 @@
 #ifndef nsDOMEvent_h__
 #define nsDOMEvent_h__
 
 #include "nsIDOMEvent.h"
 #include "nsISupports.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMEventTarget.h"
 #include "nsPIDOMWindow.h"
+#include "nsJSEnvironment.h"
 #include "nsPoint.h"
 #include "nsGUIEvent.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsAutoPtr.h"
 #include "nsIJSNativeInitializer.h"
 
 class nsIContent;
 class nsPresContext;
--- a/content/events/src/nsDOMTouchEvent.cpp
+++ b/content/events/src/nsDOMTouchEvent.cpp
@@ -126,16 +126,17 @@ nsDOMTouch::Equals(nsIDOMTouch* aTouch)
          (mRotationAngle != orientation) ||
          (mRadius.x != radiusX) || (mRadius.y != radiusY);
 }
 
 // TouchList
 nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
 {
   mPoints.AppendElements(aTouches);
+  nsJSContext::LikelyShortLivingObjectCreated();
 }
 
 DOMCI_DATA(TouchList, nsDOMTouchList)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouchList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
--- a/content/events/src/nsDOMTouchEvent.h
+++ b/content/events/src/nsDOMTouchEvent.h
@@ -5,16 +5,17 @@
 #ifndef nsDOMTouchEvent_h_
 #define nsDOMTouchEvent_h_
 
 #include "nsDOMUIEvent.h"
 #include "nsIDOMTouchEvent.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/Attributes.h"
+#include "nsJSEnvironment.h"
 
 class nsDOMTouch MOZ_FINAL : public nsIDOMTouch
 {
 public:
   nsDOMTouch(nsIDOMEventTarget* aTarget,
              int32_t aIdentifier,
              int32_t aPageX,
              int32_t aPageY,
@@ -36,16 +37,17 @@ public:
       mPointsInitialized = true;
       mRadius.x = aRadiusX;
       mRadius.y = aRadiusY;
       mRotationAngle = aRotationAngle;
       mForce = aForce;
 
       mChanged = false;
       mMessage = 0;
+      nsJSContext::LikelyShortLivingObjectCreated();
     }
   nsDOMTouch(int32_t aIdentifier,
              nsIntPoint aPoint,
              nsIntPoint aRadius,
              float aRotationAngle,
              float aForce)
     {
       mIdentifier = aIdentifier;
@@ -55,16 +57,17 @@ public:
       mRefPoint = aPoint;
       mPointsInitialized = false;
       mRadius = aRadius;
       mRotationAngle = aRotationAngle;
       mForce = aForce;
 
       mChanged = false;
       mMessage = 0;
+      nsJSContext::LikelyShortLivingObjectCreated();
     }
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouch)
   NS_DECL_NSIDOMTOUCH
   void InitializePoints(nsPresContext* aPresContext, nsEvent* aEvent)
   {
     if (mPointsInitialized) {
       return;
@@ -99,17 +102,20 @@ protected:
 
 class nsDOMTouchList MOZ_FINAL : public nsIDOMTouchList
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
   NS_DECL_NSIDOMTOUCHLIST
 
-  nsDOMTouchList() { }
+  nsDOMTouchList()
+  {
+    nsJSContext::LikelyShortLivingObjectCreated();
+  }
   nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches);
 
   void Append(nsIDOMTouch* aPoint)
   {
     mPoints.AppendElement(aPoint);
   }
 
   nsIDOMTouch* GetItemAt(uint32_t aIndex)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -156,16 +156,17 @@ static js::AnalysisPurgeCallback sPrevAn
 // have an easy place to know when a load ends or is interrupted in
 // all cases. This counter also gets reset if we end up GC'ing while
 // we're waiting for a slow page to load. IOW, this count may be 0
 // even when there are pending loads.
 static uint32_t sPendingLoadCount;
 static bool sLoadingInProgress;
 
 static uint32_t sCCollectedWaitingForGC;
+static uint32_t sLikelyShortLivingObjectsNeedingGC;
 static bool sPostGCEventsToConsole;
 static bool sPostGCEventsToObserver;
 static bool sDisableExplicitCompartmentGC;
 static uint32_t sCCTimerFireCount = 0;
 static uint32_t sMinForgetSkippableTime = UINT32_MAX;
 static uint32_t sMaxForgetSkippableTime = 0;
 static uint32_t sTotalForgetSkippableTime = 0;
 static uint32_t sRemovedPurples = 0;
@@ -3184,17 +3185,18 @@ nsJSContext::CycleCollectNow(nsICycleCol
   bool mergingCC = DoMergingCC(aForced);
 
   nsCycleCollectorResults ccResults;
   nsCycleCollector_collect(mergingCC, &ccResults, aListener);
   sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed;
 
   // If we collected a substantial amount of cycles, poke the GC since more objects
   // might be unreachable now.
-  if (sCCollectedWaitingForGC > 250) {
+  if (sCCollectedWaitingForGC > 250 ||
+      sLikelyShortLivingObjectsNeedingGC > 2500) {
     PokeGC(js::gcreason::CC_WAITING);
   }
 
   PRTime now = PR_Now();
 
   if (sLastCCEndTime) {
     uint32_t timeBetween = (uint32_t)(start - sLastCCEndTime) / PR_USEC_PER_SEC;
     Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
@@ -3217,24 +3219,25 @@ nsJSContext::CycleCollectNow(nsICycleCol
     }
 
     nsCString gcMsg;
     if (ccResults.mForcedGC) {
       gcMsg.AssignLiteral(", forced a GC");
     }
 
     NS_NAMED_MULTILINE_LITERAL_STRING(kFmt,
-      NS_LL("CC(T+%.1f) duration: %llums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu waiting for GC)%s\n")
+      NS_LL("CC(T+%.1f) duration: %llums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu waiting for GC)%s\n")
       NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, removed: %lu"));
     nsString msg;
     msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC,
                                         (now - start) / PR_USEC_PER_MSEC, suspected,
                                         ccResults.mVisitedRefCounted, ccResults.mVisitedGCed, mergeMsg.get(),
                                         ccResults.mFreedRefCounted, ccResults.mFreedGCed,
-                                        sCCollectedWaitingForGC, gcMsg.get(),
+                                        sCCollectedWaitingForGC, sLikelyShortLivingObjectsNeedingGC,
+                                        gcMsg.get(),
                                         sForgetSkippableBeforeCC,
                                         minForgetSkippableTime / PR_USEC_PER_MSEC,
                                         sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
                                         (sTotalForgetSkippableTime / cleanups) /
                                           PR_USEC_PER_MSEC,
                                         sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
                                         sRemovedPurples));
     nsCOMPtr<nsIConsoleService> cs =
@@ -3251,31 +3254,33 @@ nsJSContext::CycleCollectNow(nsICycleCol
          NS_LL("\"suspected\": %lu, ")
          NS_LL("\"visited\": { ")
              NS_LL("\"RCed\": %lu, ")
              NS_LL("\"GCed\": %lu }, ")
          NS_LL("\"collected\": { ")
              NS_LL("\"RCed\": %lu, ")
              NS_LL("\"GCed\": %lu }, ")
          NS_LL("\"waiting_for_gc\": %lu, ")
+         NS_LL("\"short_living_objects_waiting_for_gc\": %lu, ")
          NS_LL("\"forced_gc\": %d, ")
          NS_LL("\"forget_skippable\": { ")
              NS_LL("\"times_before_cc\": %lu, ")
              NS_LL("\"min\": %lu, ")
              NS_LL("\"max\": %lu, ")
              NS_LL("\"avg\": %lu, ")
              NS_LL("\"total\": %lu, ")
              NS_LL("\"removed\": %lu } ")
        NS_LL("}"));
     nsString json;
     json.Adopt(nsTextFormatter::smprintf(kJSONFmt.get(),
                                          now, (now - start) / PR_USEC_PER_MSEC, suspected,
                                          ccResults.mVisitedRefCounted, ccResults.mVisitedGCed,
                                          ccResults.mFreedRefCounted, ccResults.mFreedGCed,
                                          sCCollectedWaitingForGC,
+                                         sLikelyShortLivingObjectsNeedingGC,
                                          ccResults.mForcedGC,
                                          sForgetSkippableBeforeCC,
                                          minForgetSkippableTime / PR_USEC_PER_MSEC,
                                          sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
                                          (sTotalForgetSkippableTime / cleanups) /
                                            PR_USEC_PER_MSEC,
                                          sTotalForgetSkippableTime / PR_USEC_PER_MSEC,
                                          sRemovedPurples));
@@ -3631,16 +3636,17 @@ DOMGCSliceCallback(JSRuntime *aRt, js::G
                                              nsITimer::TYPE_ONE_SHOT);
   }
 
   if (aProgress == js::GC_CYCLE_END) {
     // May need to kill the inter-slice GC timer
     nsJSContext::KillInterSliceGCTimer();
 
     sCCollectedWaitingForGC = 0;
+    sLikelyShortLivingObjectsNeedingGC = 0;
     sCleanupsSinceLastGC = 0;
     sNeedsFullCC = true;
     nsJSContext::MaybePokeCC();
 
     if (aDesc.isCompartment) {
       ++sCompartmentGCCount;
       if (!sFullGCTimer) {
         CallCreateInstance("@mozilla.org/timer;1", &sFullGCTimer);
@@ -3726,16 +3732,22 @@ nsJSContext::ReportPendingException()
   if (mIsInitialized && ::JS_IsExceptionPending(mContext)) {
     bool saved = ::JS_SaveFrameChain(mContext);
     ::JS_ReportPendingException(mContext);
     if (saved)
         ::JS_RestoreFrameChain(mContext);
   }
 }
 
+void
+nsJSContext::LikelyShortLivingObjectCreated()
+{
+  ++sLikelyShortLivingObjectsNeedingGC;
+}
+
 /**********************************************************************
  * nsJSRuntime implementation
  *********************************************************************/
 
 // QueryInterface implementation for nsJSRuntime
 NS_INTERFACE_MAP_BEGIN(nsJSRuntime)
   NS_INTERFACE_MAP_ENTRY(nsIScriptRuntime)
 NS_INTERFACE_MAP_END
@@ -3758,16 +3770,17 @@ nsJSRuntime::Startup()
   // initialize all our statics, so that we can restart XPCOM
   sGCTimer = sFullGCTimer = sCCTimer = nullptr;
   sCCLockedOut = false;
   sCCLockedOutTime = 0;
   sLastCCEndTime = 0;
   sPendingLoadCount = 0;
   sLoadingInProgress = false;
   sCCollectedWaitingForGC = 0;
+  sLikelyShortLivingObjectsNeedingGC = 0;
   sPostGCEventsToConsole = false;
   sDisableExplicitCompartmentGC = false;
   sNeedsFullCC = false;
   gNameSpaceManager = nullptr;
   gReporter = nullptr;
   sRuntimeService = nullptr;
   sRuntime = nullptr;
   sIsInitialized = false;
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -182,16 +182,19 @@ public:
   static void PokeShrinkGCBuffers();
   static void KillShrinkGCBuffersTimer();
 
   static void MaybePokeCC();
   static void KillCCTimer();
   static void KillFullGCTimer();
   static void KillInterSliceGCTimer();
 
+  // Calling LikelyShortLivingObjectCreated() makes a GC more likely.
+  static void LikelyShortLivingObjectCreated();
+
   virtual void GC(js::gcreason::Reason aReason);
 
   static uint32_t CleanupsSinceLastGC();
 
   nsIScriptGlobalObject* GetCachedGlobalObject()
   {
     // Verify that we have a global so that this
     // does always return a null when GetGlobalObject() is null.