Bug 903519 - Discard nursery keys from EvalCache, r=jonco
☠☠ backed out by 65e92478e09d ☠ ☠
authorSteve Fink <sfink@mozilla.com>
Thu, 03 Aug 2017 16:18:47 -0700
changeset 453157 f5f72c93adf94f4ae670c38941f68c75d19f8072
parent 453156 7d56db66836900bc7758c6829b9235a3dd26947e
child 453158 7854bfe5d68346a38b25d93ea8870f47bce4f901
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs903519
milestone59.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 903519 - Discard nursery keys from EvalCache, r=jonco
js/src/gc/GCRuntime.h
js/src/gc/Nursery.cpp
js/src/gc/Nursery.h
js/src/jsgc.cpp
js/src/vm/Caches.h
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -791,16 +791,18 @@ class GCRuntime
 
     enum TraceOrMarkRuntime {
         TraceRuntime,
         MarkRuntime
     };
     void traceRuntime(JSTracer* trc, AutoLockForExclusiveAccess& lock);
     void traceRuntimeForMinorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock);
 
+    void purgeRuntimeForMinorGC();
+
     void shrinkBuffers();
     void onOutOfMallocMemory();
     void onOutOfMallocMemory(const AutoLockGC& lock);
 
 #ifdef JS_GC_ZEAL
     const void* addressOfZealModeBits() { return &zealModeBits; }
     void getZealBits(uint32_t* zealBits, uint32_t* frequency, uint32_t* nextScheduled);
     void setZeal(uint8_t zeal, uint32_t frequency);
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -829,19 +829,19 @@ js::Nursery::doCollection(JS::gcreason::
 
     startProfile(ProfileKey::MarkDebugger);
     {
         gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::MARK_ROOTS);
         Debugger::traceAllForMovingGC(&mover);
     }
     endProfile(ProfileKey::MarkDebugger);
 
-    startProfile(ProfileKey::ClearNewObjectCache);
-    rt->caches().newObjectCache.clearNurseryObjects(rt);
-    endProfile(ProfileKey::ClearNewObjectCache);
+    startProfile(ProfileKey::SweepCaches);
+    rt->gc.purgeRuntimeForMinorGC();
+    endProfile(ProfileKey::SweepCaches);
 
     // 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);
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -23,17 +23,17 @@
     _(TraceValues,              "mkVals")                                     \
     _(TraceCells,               "mkClls")                                     \
     _(TraceSlots,               "mkSlts")                                     \
     _(TraceWholeCells,          "mcWCll")                                     \
     _(TraceGenericEntries,      "mkGnrc")                                     \
     _(CheckHashTables,          "ckTbls")                                     \
     _(MarkRuntime,              "mkRntm")                                     \
     _(MarkDebugger,             "mkDbgr")                                     \
-    _(ClearNewObjectCache,      "clrNOC")                                     \
+    _(SweepCaches,              "swpCch")                                     \
     _(CollectToFP,              "collct")                                     \
     _(ObjectsTenuredCallback,   "tenCB")                                      \
     _(Sweep,                    "sweep")                                      \
     _(UpdateJitActivations,     "updtIn")                                     \
     _(FreeMallocedBuffers,      "frSlts")                                     \
     _(ClearStoreBuffer,         "clrSB")                                      \
     _(ClearNursery,             "clear")                                      \
     _(Pretenure,                "pretnr")
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3880,16 +3880,29 @@ class MOZ_RAII js::gc::AutoRunParallelTa
     }
 
     void run() override {
         func_(runtime());
     }
 };
 
 void
+GCRuntime::purgeRuntimeForMinorGC()
+{ 
+    // If external strings become nursery allocable, remember to call
+    // zone->externalStringCache().purge() (and delete this assert.)
+    MOZ_ASSERT(!IsNurseryAllocable(AllocKind::EXTERNAL_STRING));
+
+    for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next())
+        zone->functionToStringCache().purge();
+
+    rt->caches().purgeForMinorGC(rt);
+}
+
+void
 GCRuntime::purgeRuntime(AutoLockForExclusiveAccess& lock)
 {
     gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::PURGE);
 
     for (GCCompartmentsIter comp(rt); !comp.done(); comp.next())
         comp->purge();
 
     for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
@@ -3899,22 +3912,17 @@ GCRuntime::purgeRuntime(AutoLockForExclu
     }
 
     for (const CooperatingContext& target : rt->cooperatingContexts()) {
         freeUnusedLifoBlocksAfterSweeping(&target.context()->tempLifoAlloc());
         target.context()->interpreterStack().purge(rt);
         target.context()->frontendCollectionPool().purge();
     }
 
-    rt->caches().gsnCache.purge();
-    rt->caches().envCoordinateNameCache.purge();
-    rt->caches().newObjectCache.purge();
-    rt->caches().uncompressedSourceCache.purge();
-    if (rt->caches().evalCache.initialized())
-        rt->caches().evalCache.clear();
+    rt->caches().purge();
 
     if (auto cache = rt->maybeThisRuntimeSharedImmutableStrings())
         cache->purge();
 
     MOZ_ASSERT(unmarkGrayStack.empty());
     unmarkGrayStack.clearAndFree();
 }
 
@@ -6569,19 +6577,17 @@ GCRuntime::compactPhase(JS::gcreason::Re
     }
 
     if (ShouldProtectRelocatedArenas(reason))
         protectAndHoldArenas(relocatedArenas);
     else
         releaseRelocatedArenas(relocatedArenas);
 
     // Clear caches that can contain cell pointers.
-    rt->caches().newObjectCache.purge();
-    if (rt->caches().evalCache.initialized())
-        rt->caches().evalCache.clear();
+    rt->caches().purgeForCompaction();
 
 #ifdef DEBUG
     CheckHashTablesAfterMovingGC(rt);
 #endif
 
     return zonesToMaybeCompact.ref().isEmpty() ? Finished : NotFinished;
 }
 
--- a/js/src/vm/Caches.h
+++ b/js/src/vm/Caches.h
@@ -59,16 +59,25 @@ struct EnvironmentCoordinateNameCache {
 };
 
 struct EvalCacheEntry
 {
     JSLinearString* str;
     JSScript* script;
     JSScript* callerScript;
     jsbytecode* pc;
+
+    // We sweep this cache before a nursery collection to remove entries with
+    // string keys in the nursery.
+    //
+    // The entire cache is purged on a major GC, so we don't need to sweep it
+    // then.
+    bool needsSweep() {
+        return !str->isTenured();
+    }
 };
 
 struct EvalCacheLookup
 {
     explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
     RootedLinearString str;
     RootedScript callerScript;
     jsbytecode* pc;
@@ -77,17 +86,17 @@ struct EvalCacheLookup
 struct EvalCacheHashPolicy
 {
     typedef EvalCacheLookup Lookup;
 
     static HashNumber hash(const Lookup& l);
     static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
 };
 
-typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
+typedef GCHashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
 
 /*
  * Cache for speeding up repetitive creation of objects in the VM.
  * When an object is created which matches the criteria in the 'key' section
  * below, an entry is filled with the resulting object.
  */
 class NewObjectCache
 {
@@ -231,13 +240,31 @@ class RuntimeCaches
     bool init();
 
     js::MathCache* getMathCache(JSContext* cx) {
         return mathCache_ ? mathCache_.get() : createMathCache(cx);
     }
     js::MathCache* maybeGetMathCache() {
         return mathCache_.get();
     }
+
+    void purgeForMinorGC(JSRuntime* rt) {
+        newObjectCache.clearNurseryObjects(rt);
+        evalCache.sweep();
+    }
+
+    void purgeForCompaction() {
+        newObjectCache.purge();
+        if (evalCache.initialized())
+            evalCache.clear();
+    }
+
+    void purge() {
+        purgeForCompaction();
+        gsnCache.purge();
+        envCoordinateNameCache.purge();
+        uncompressedSourceCache.purge();
+    }
 };
 
 } // namespace js
 
 #endif /* vm_Caches_h */