Bug 807535 - Avoid toggling Ion write barrier too often (r=sstangl,a=bajaj)
authorBill McCloskey <wmccloskey@mozilla.com>
Thu, 01 Nov 2012 08:08:21 -0700
changeset 114073 bf7ed9f18a09351c091e149a1e866bbfe7ff24eb
parent 114072 4ae139ff61c8044d2275ca11a11c9c0227f639e0
child 114074 f32f5bf29668162bda7d4540ceb6936898fa1382
push id2632
push userwmccloskey@mozilla.com
push dateFri, 09 Nov 2012 18:24:47 +0000
treeherdermozilla-aurora@f32f5bf29668 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl, bajaj
bugs807535
milestone18.0a2
Bug 807535 - Avoid toggling Ion write barrier too often (r=sstangl,a=bajaj)
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
@@ -4157,17 +4157,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();
@@ -4215,35 +4215,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
@@ -4390,17 +4395,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) {}
 
@@ -5346,17 +5351,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();
@@ -5429,17 +5434,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++;