Bug 807535 - Avoid toggling Ion write barrier too often (r=sstangl)
authorBill McCloskey <wmccloskey@mozilla.com>
Thu, 01 Nov 2012 08:08:21 -0700
changeset 112050 23eb7d58bf903ca85b103491931323d9c875d913
parent 112049 5950e455f4c38e4072260ba094b70001a68665a3
child 112051 cc21ea546a26d1c405ec6d67b604f9e74e5dae7f
push id23790
push userryanvm@gmail.com
push dateFri, 02 Nov 2012 01:26:40 +0000
treeherdermozilla-central@556b9cfb269f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs807535
milestone19.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 807535 - Avoid toggling Ion write barrier too often (r=sstangl)
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsgc.cpp
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -43,16 +43,17 @@ using namespace js::gc;
 JSCompartment::JSCompartment(JSRuntime *rt)
   : rt(rt),
     principals(NULL),
     global_(NULL),
 #ifdef JSGC_GENERATIONAL
     gcStoreBuffer(&gcNursery),
 #endif
     needsBarrier_(false),
+    ionUsingBarriers_(false),
     gcScheduled(false),
     gcState(NoGC),
     gcPreserveCode(false),
     gcBytes(0),
     gcTriggerBytes(0),
     gcHeapGrowthFactor(3.0),
     gcNextCompartment(NULL),
     hold(false),
@@ -126,28 +127,30 @@ JSCompartment::init(JSContext *cx)
         gcStoreBuffer.disable();
     }
 #endif
 
     return debuggees.init();
 }
 
 void
-JSCompartment::setNeedsBarrier(bool needs)
+JSCompartment::setNeedsBarrier(bool needs, ShouldUpdateIon updateIon)
 {
 #ifdef JS_METHODJIT
     /* ClearAllFrames calls compileBarriers() and needs the old value. */
     bool old = compileBarriers();
     if (compileBarriers(needs) != old)
         mjit::ClearAllFrames(this);
 #endif
 
 #ifdef JS_ION
-    if (needsBarrier_ != needs)
+    if (updateIon == UpdateIon && needs != ionUsingBarriers_) {
         ion::ToggleBarriers(this, needs);
+        ionUsingBarriers_ = needs;
+    }
 #endif
 
     needsBarrier_ = needs;
 }
 
 #ifdef JS_ION
 bool
 JSCompartment::ensureIonCompartmentExists(JSContext *cx)
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -150,31 +150,37 @@ struct JSCompartment
 
 #ifdef JSGC_GENERATIONAL
     js::gc::Nursery              gcNursery;
     js::gc::StoreBuffer          gcStoreBuffer;
 #endif
 
   private:
     bool                         needsBarrier_;
+    bool                         ionUsingBarriers_;
   public:
 
     bool needsBarrier() const {
         return needsBarrier_;
     }
 
     bool compileBarriers(bool needsBarrier) const {
         return needsBarrier || rt->gcZeal() == js::gc::ZealVerifierPreValue;
     }
 
     bool compileBarriers() const {
         return compileBarriers(needsBarrier());
     }
 
-    void setNeedsBarrier(bool needs);
+    enum ShouldUpdateIon {
+        DontUpdateIon,
+        UpdateIon
+    };
+
+    void setNeedsBarrier(bool needs, ShouldUpdateIon updateIon);
 
     static size_t OffsetOfNeedsBarrier() {
         return offsetof(JSCompartment, needsBarrier_);
     }
 
     js::GCMarker *barrierTracer() {
         JS_ASSERT(needsBarrier_);
         return &rt->gcMarker;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4074,17 +4074,17 @@ ResetIncrementalGC(JSRuntime *rt, const 
         return;
 
     /* Cancel and ongoing marking. */
     bool wasMarking = false;
     {
         AutoCopyFreeListToArenas copy(rt);
         for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
             if (c->isGCMarking()) {
-                c->setNeedsBarrier(false);
+                c->setNeedsBarrier(false, JSCompartment::DontUpdateIon);
                 c->setGCState(JSCompartment::NoGC);
                 wasMarking = true;
             }
         }
     }
 
     if (wasMarking)
         rt->gcMarker.reset();
@@ -4132,35 +4132,40 @@ AutoGCSlice::AutoGCSlice(JSRuntime *rt)
      * During incremental GC, the compartment's active flag determines whether
      * there are stack frames active for any of its scripts. Normally this flag
      * is set at the beginning of the mark phase. During incremental GC, we also
      * set it at the start of every phase.
      */
     rt->stackSpace.markActiveCompartments();
 
     for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
-        /* Clear this early so we don't do any write barriers during GC. */
+        /*
+         * Clear needsBarrier early so we don't do any write barriers during
+         * GC. We don't need to update the Ion barriers (which is expensive)
+         * because Ion code doesn't run during GC. If need be, we'll update the
+         * Ion barriers in ~AutoGCSlice.
+         */
         if (c->isGCMarking()) {
             JS_ASSERT(c->needsBarrier());
-            c->setNeedsBarrier(false);
+            c->setNeedsBarrier(false, JSCompartment::DontUpdateIon);
         } else {
             JS_ASSERT(!c->needsBarrier());
         }
     }
 }
 
 AutoGCSlice::~AutoGCSlice()
 {
     for (GCCompartmentsIter c(runtime); !c.done(); c.next()) {
         if (c->isGCMarking()) {
-            c->setNeedsBarrier(true);
+            c->setNeedsBarrier(true, JSCompartment::UpdateIon);
             c->arenas.prepareForIncrementalGC(runtime);
         } else {
             JS_ASSERT(c->isGCSweeping());
-            c->setNeedsBarrier(false);
+            c->setNeedsBarrier(false, JSCompartment::UpdateIon);
         }
     }
 }
 
 static void
 PushZealSelectedObjects(JSRuntime *rt)
 {
 #ifdef JS_GC_ZEAL
@@ -4307,17 +4312,17 @@ IncrementalCollectSlice(JSRuntime *rt,
         if (rt->gcSweepOnBackgroundThread)
             rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK);
 
         rt->gcIncrementalState = NO_INCREMENTAL;
         break;
 
       default:
         JS_ASSERT(false);
-     }
+    }
 }
 
 class IncrementalSafety
 {
     const char *reason_;
 
     IncrementalSafety(const char *reason) : reason_(reason) {}
 
@@ -5262,17 +5267,17 @@ StartVerifyPreBarriers(JSRuntime *rt)
         node = NextNode(node);
     }
 
     rt->gcVerifyPreData = trc;
     rt->gcIncrementalState = MARK;
     rt->gcMarker.start(rt);
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         PurgeJITCaches(c);
-        c->setNeedsBarrier(true);
+        c->setNeedsBarrier(true, JSCompartment::UpdateIon);
         c->arenas.purge();
     }
 
     return;
 
 oom:
     rt->gcIncrementalState = NO_INCREMENTAL;
     trc->~VerifyPreTracer();
@@ -5345,17 +5350,17 @@ EndVerifyPreBarriers(JSRuntime *rt)
     bool compartmentCreated = false;
 
     /* We need to disable barriers before tracing, which may invoke barriers. */
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         if (!c->needsBarrier())
             compartmentCreated = true;
 
         PurgeJITCaches(c);
-        c->setNeedsBarrier(false);
+        c->setNeedsBarrier(false, JSCompartment::UpdateIon);
     }
 
     /*
      * We need to bump gcNumber so that the methodjit knows that jitcode has
      * been discarded.
      */
     JS_ASSERT(trc->number == rt->gcNumber);
     rt->gcNumber++;