Bug 1293262 - Always pre-tenure objects after minor GC r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Tue, 09 Aug 2016 10:23:01 +0100
changeset 398556 5df7daac885a736f269f831673d8dfe88e7894ff
parent 398555 547340fb951dbfc522c9b28c215a7ee31a144e40
child 398557 2b81703d0d0ead8d9d4afcfaeb04b7d7b853ae08
push id25572
push userbmo:rail@mozilla.com
push dateTue, 09 Aug 2016 13:05:34 +0000
reviewersterrence
bugs1293262
milestone51.0a1
Bug 1293262 - Always pre-tenure objects after minor GC r=terrence
js/src/gc/Allocator.cpp
js/src/gc/GCRuntime.h
js/src/jscntxt.h
js/src/jsgc.cpp
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -79,17 +79,17 @@ GCRuntime::tryNewNurseryObject(JSContext
     MOZ_ASSERT(isNurseryAllocAllowed());
     MOZ_ASSERT(!cx->zone()->usedByExclusiveThread);
     MOZ_ASSERT(!IsAtomsCompartment(cx->compartment()));
     JSObject* obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
     if (obj)
         return obj;
 
     if (allowGC && !rt->mainThread.suppressGC) {
-        minorGC(cx, JS::gcreason::OUT_OF_NURSERY);
+        minorGC(JS::gcreason::OUT_OF_NURSERY);
 
         // Exceeding gcMaxBytes while tenuring can disable the Nursery.
         if (nursery.isEnabled()) {
             JSObject* obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
             MOZ_ASSERT(obj);
             return obj;
         }
     }
@@ -222,17 +222,17 @@ GCRuntime::gcIfNeededPerAllocation(JSCon
 #ifdef JS_GC_ZEAL
     if (needZealousGC())
         runDebugGC();
 #endif
 
     // Invoking the interrupt callback can fail and we can't usefully
     // handle that here. Just check in case we need to collect instead.
     if (rt->hasPendingInterrupt())
-        gcIfRequested(cx);
+        gcIfRequested();
 
     // If we have grown past our GC heap threshold while in the middle of
     // an incremental GC, we're growing faster than we're GCing, so stop
     // the world and do a full, non-incremental GC right now, if possible.
     if (isIncrementalGCInProgress() &&
         cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes())
     {
         PrepareZoneForGC(cx->zone());
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -620,27 +620,23 @@ class GCRuntime
     uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
 
     MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
     void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
     // The return value indicates if we were able to do the GC.
     bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason);
     MOZ_MUST_USE bool maybeGC(Zone* zone);
     void maybePeriodicFullGC();
-    void minorGC(JS::gcreason::Reason reason) {
-        gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC);
-        minorGCImpl(reason, nullptr);
-    }
-    void minorGC(JSContext* cx, JS::gcreason::Reason reason);
+    void minorGC(JS::gcreason::Reason reason,
+                 gcstats::Phase phase = gcstats::PHASE_MINOR_GC) JS_HAZ_GC_CALL;
     void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) {
-        gcstats::AutoPhase ap(stats, gcstats::PHASE_EVICT_NURSERY);
-        minorGCImpl(reason, nullptr);
+        minorGC(reason, gcstats::PHASE_EVICT_NURSERY);
     }
     // The return value indicates whether a major GC was performed.
-    bool gcIfRequested(JSContext* cx = nullptr);
+    bool gcIfRequested();
     void gc(JSGCInvocationKind gckind, JS::gcreason::Reason reason);
     void startGC(JSGCInvocationKind gckind, JS::gcreason::Reason reason, int64_t millis = 0);
     void gcSlice(JS::gcreason::Reason reason, int64_t millis = 0);
     void finishGC(JS::gcreason::Reason reason);
     void abortGC();
     void startDebugGC(JSGCInvocationKind gckind, SliceBudget& budget);
     void debugGCSlice(SliceBudget& budget);
 
@@ -885,18 +881,16 @@ class GCRuntime
 
   private:
     enum IncrementalProgress
     {
         NotFinished = 0,
         Finished
     };
 
-    void minorGCImpl(JS::gcreason::Reason reason, Nursery::ObjectGroupList* pretenureGroups) JS_HAZ_GC_CALL;
-
     // For ArenaLists::allocateFromArena()
     friend class ArenaLists;
     Chunk* pickChunk(const AutoLockGC& lock,
                      AutoMaybeStartBackgroundAllocation& maybeStartBGAlloc);
     Arena* allocateArena(Chunk* chunk, Zone* zone, AllocKind kind, const AutoLockGC& lock);
     void arenaAllocatedDuringGC(JS::Zone* zone, Arena* arena);
 
     // Allocator internals
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -445,17 +445,17 @@ struct JSContext : public js::ExclusiveC
                                    MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
 
     // The generational GC nursery may only be used on the main thread.
     inline js::Nursery& nursery() {
         return gc.nursery;
     }
 
     void minorGC(JS::gcreason::Reason reason) {
-        gc.minorGC(this, reason);
+        gc.minorGC(reason);
     }
 
   public:
     bool isExceptionPending() {
         return throwing;
     }
 
     MOZ_MUST_USE
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -6462,53 +6462,52 @@ GCRuntime::onOutOfMallocMemory(const Aut
 
     // Immediately decommit as many arenas as possible in the hopes that this
     // might let the OS scrape together enough pages to satisfy the failing
     // malloc request.
     decommitAllWithoutUnlocking(lock);
 }
 
 void
-GCRuntime::minorGCImpl(JS::gcreason::Reason reason, Nursery::ObjectGroupList* pretenureGroups)
+GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::Phase phase)
 {
     MOZ_ASSERT(!rt->isHeapBusy());
 
     if (rt->mainThread.suppressGC)
         return;
 
+    gcstats::AutoPhase ap(stats, phase);
+
     minorGCTriggerReason = JS::gcreason::NO_REASON;
     TraceLoggerThread* logger = TraceLoggerForMainThread(rt);
     AutoTraceLog logMinorGC(logger, TraceLogger_MinorGC);
-    nursery.collect(rt, reason, pretenureGroups);
+    Nursery::ObjectGroupList pretenureGroups;
+    nursery.collect(rt, reason, &pretenureGroups);
     MOZ_ASSERT(nursery.isEmpty());
 
     blocksToFreeAfterMinorGC.freeAll();
 
 #ifdef JS_GC_ZEAL
     if (rt->hasZealMode(ZealMode::CheckHeapOnMovingGC))
         CheckHeapAfterMovingGC(rt);
 #endif
 
-    AutoLockGC lock(rt);
-    for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
-        maybeAllocTriggerZoneGC(zone, lock);
-}
-
-// Alternate to the runtime-taking form that allows marking object groups as
-// needing pretenuring.
-void
-GCRuntime::minorGC(JSContext* cx, JS::gcreason::Reason reason)
-{
-    gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC);
-
-    Nursery::ObjectGroupList pretenureGroups;
-    minorGCImpl(reason, &pretenureGroups);
+    JSContext* cx = rt->contextFromMainThread();
     for (size_t i = 0; i < pretenureGroups.length(); i++) {
-        if (pretenureGroups[i]->canPreTenure())
-            pretenureGroups[i]->setShouldPreTenure(cx);
+        ObjectGroup* group = pretenureGroups[i];
+        if (group->canPreTenure()) {
+            AutoCompartment ac(cx, group->compartment());
+            group->setShouldPreTenure(cx);
+        }
+    }
+
+    {
+        AutoLockGC lock(rt);
+        for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
+            maybeAllocTriggerZoneGC(zone, lock);
     }
 }
 
 void
 GCRuntime::disableGenerationalGC()
 {
     if (isGenerationalGCEnabled()) {
         evictNursery(JS::gcreason::API);
@@ -6525,26 +6524,22 @@ GCRuntime::enableGenerationalGC()
     --generationalDisabled;
     if (generationalDisabled == 0) {
         nursery.enable();
         storeBuffer.enable();
     }
 }
 
 bool
-GCRuntime::gcIfRequested(JSContext* cx /* = nullptr */)
+GCRuntime::gcIfRequested()
 {
     // This method returns whether a major GC was performed.
 
-    if (minorGCRequested()) {
-        if (cx)
-            minorGC(cx, minorGCTriggerReason);
-        else
-            minorGC(minorGCTriggerReason);
-    }
+    if (minorGCRequested())
+        minorGC(minorGCTriggerReason);
 
     if (majorGCRequested()) {
         if (!isIncrementalGCInProgress())
             startGC(GC_NORMAL, majorGCTriggerReason);
         else
             gcSlice(majorGCTriggerReason);
         return true;
     }