Bug 928056 - Do not pause for background compilation before ggc; r=bhackett,r=billm
authorTerrence Cole <terrence@mozilla.com>
Thu, 17 Oct 2013 14:42:46 -0700
changeset 166371 b1ce503713893db81a58156546d3d06b3e29066b
parent 166370 110171f903b1fce098a2fb45ac5fbda1ed108e0d
child 166372 0bd2b4b3f71583f2880ca4007cb2cfc4ae8f3e21
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett, billm
bugs928056
milestone27.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 928056 - Do not pause for background compilation before ggc; r=bhackett,r=billm
js/src/gc/GCInternals.h
js/src/gc/Iteration.cpp
js/src/jsgc.cpp
js/src/jsworkers.cpp
js/src/jsworkers.h
js/src/vm/Runtime.h
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -15,52 +15,54 @@ namespace js {
 namespace gc {
 
 void
 MarkRuntime(JSTracer *trc, bool useSavedRoots = false);
 
 void
 BufferGrayRoots(GCMarker *gcmarker);
 
-class AutoCopyFreeListToArenas {
+class AutoCopyFreeListToArenas
+{
     JSRuntime *runtime;
 
   public:
     AutoCopyFreeListToArenas(JSRuntime *rt);
     ~AutoCopyFreeListToArenas();
 };
 
 struct AutoFinishGC
 {
     AutoFinishGC(JSRuntime *rt);
 };
 
 /*
  * This class should be used by any code that needs to exclusive access to the
  * heap in order to trace through it...
  */
-class AutoTraceSession {
+class AutoTraceSession
+{
   public:
     AutoTraceSession(JSRuntime *rt, HeapState state = Tracing);
     ~AutoTraceSession();
 
   protected:
     JSRuntime *runtime;
 
   private:
     AutoTraceSession(const AutoTraceSession&) MOZ_DELETE;
     void operator=(const AutoTraceSession&) MOZ_DELETE;
 
     js::HeapState prevState;
-    AutoPauseWorkersForGC pause;
 };
 
 struct AutoPrepareForTracing
 {
     AutoFinishGC finish;
+    AutoPauseWorkersForTracing pause;
     AutoTraceSession session;
     AutoCopyFreeListToArenas copy;
 
     AutoPrepareForTracing(JSRuntime *rt);
 };
 
 class IncrementalSafety
 {
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -99,13 +99,14 @@ js::IterateGrayObjects(Zone *zone, GCThi
 }
 
 JS_PUBLIC_API(void)
 JS_IterateCompartments(JSRuntime *rt, void *data,
                        JSIterateCompartmentCallback compartmentCallback)
 {
     JS_ASSERT(!rt->isHeapBusy());
 
+    AutoPauseWorkersForTracing pause(rt);
     AutoTraceSession session(rt);
 
     for (CompartmentsIter c(rt); !c.done(); c.next())
         (*compartmentCallback)(rt, data, c);
 }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4071,44 +4071,50 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocat
     FinishMarkingValidation(rt);
 
     rt->gcLastGCTime = PRMJ_Now();
 }
 
 namespace {
 
 /* ...while this class is to be used only for garbage collection. */
-class AutoGCSession : AutoTraceSession {
+class AutoGCSession
+{
+    JSRuntime *runtime;
+    AutoPauseWorkersForTracing pause;
+    AutoTraceSession session;
+
   public:
     explicit AutoGCSession(JSRuntime *rt);
     ~AutoGCSession();
 };
 
 } /* anonymous namespace */
 
 /* Start a new heap session. */
 AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState)
   : runtime(rt),
-    prevState(rt->heapState),
-    pause(rt)
+    prevState(rt->heapState)
 {
     JS_ASSERT(!rt->noGCOrAllocationCheck);
     JS_ASSERT(!rt->isHeapBusy());
     JS_ASSERT(heapState != Idle);
     rt->heapState = heapState;
 }
 
 AutoTraceSession::~AutoTraceSession()
 {
     JS_ASSERT(runtime->isHeapBusy());
     runtime->heapState = prevState;
 }
 
 AutoGCSession::AutoGCSession(JSRuntime *rt)
-  : AutoTraceSession(rt, MajorCollecting)
+  : runtime(rt),
+    pause(rt),
+    session(rt, MajorCollecting)
 {
     runtime->gcIsNeeded = false;
     runtime->gcInterFrameGC = true;
 
     runtime->gcNumber++;
 
 #ifdef DEBUG
     // Threads with an exclusive context should never pause while they are in
@@ -4783,16 +4789,17 @@ AutoFinishGC::AutoFinishGC(JSRuntime *rt
         JS::FinishIncrementalGC(rt, JS::gcreason::API);
     }
 
     gc::FinishBackgroundFinalize(rt);
 }
 
 AutoPrepareForTracing::AutoPrepareForTracing(JSRuntime *rt)
   : finish(rt),
+    pause(rt),
     session(rt),
     copy(rt)
 {
     RecordNativeStackTopForGC(rt);
 }
 
 JSCompartment *
 js::NewCompartment(JSContext *cx, Zone *zone, JSPrincipals *principals,
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -922,17 +922,18 @@ WorkerThread::threadLoop()
             handleParseWorkload(state);
         else if (state.canStartCompressionTask())
             handleCompressionWorkload(state);
         else
             MOZ_ASSUME_UNREACHABLE("No task to perform");
     }
 }
 
-AutoPauseWorkersForGC::AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+AutoPauseWorkersForTracing::AutoPauseWorkersForTracing(JSRuntime *rt
+                                                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : runtime(rt), needsUnpause(false), oldExclusiveThreadsPaused(rt->exclusiveThreadsPaused)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
     rt->exclusiveThreadsPaused = true;
 
     if (!runtime->workerThreadState)
         return;
@@ -940,33 +941,33 @@ AutoPauseWorkersForGC::AutoPauseWorkersF
     JS_ASSERT(CurrentThreadCanAccessRuntime(runtime));
 
     WorkerThreadState &state = *runtime->workerThreadState;
     if (!state.numThreads)
         return;
 
     AutoLockWorkerThreadState lock(state);
 
-    // Tolerate reentrant use of AutoPauseWorkersForGC.
+    // Tolerate reentrant use of AutoPauseWorkersForTracing.
     if (state.shouldPause) {
         JS_ASSERT(state.numPaused == state.numThreads);
         return;
     }
 
     needsUnpause = true;
 
     state.shouldPause = 1;
 
     while (state.numPaused != state.numThreads) {
         state.notifyAll(WorkerThreadState::PRODUCER);
         state.wait(WorkerThreadState::CONSUMER);
     }
 }
 
-AutoPauseWorkersForGC::~AutoPauseWorkersForGC()
+AutoPauseWorkersForTracing::~AutoPauseWorkersForTracing()
 {
     runtime->exclusiveThreadsPaused = oldExclusiveThreadsPaused;
 
     if (!needsUnpause)
         return;
 
     WorkerThreadState &state = *runtime->workerThreadState;
     AutoLockWorkerThreadState lock(state);
@@ -981,17 +982,17 @@ AutoPauseCurrentWorkerThread::AutoPauseC
                                                            MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : cx(cx)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
     // If the current thread is a worker thread, treat it as paused while
     // the caller is waiting for another worker thread to complete. Otherwise
     // we will not wake up and mark this as paused due to the loop in
-    // AutoPauseWorkersForGC.
+    // AutoPauseWorkersForTracing.
     if (cx->workerThread()) {
         WorkerThreadState &state = *cx->workerThreadState();
         JS_ASSERT(state.isLocked());
 
         state.numPaused++;
         if (state.numPaused == state.numThreads)
             state.notifyAll(WorkerThreadState::CONSUMER);
     }
@@ -1081,22 +1082,23 @@ SourceCompressionTask::complete()
 
 const jschar *
 ScriptSource::getOffThreadCompressionChars(ExclusiveContext *cx)
 {
     JS_ASSERT(ready());
     return nullptr;
 }
 
-AutoPauseWorkersForGC::AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+AutoPauseWorkersForTracing::AutoPauseWorkersForTracing(JSRuntime *rt
+                                                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 }
 
-AutoPauseWorkersForGC::~AutoPauseWorkersForGC()
+AutoPauseWorkersForTracing::~AutoPauseWorkersForTracing()
 {
 }
 
 AutoPauseCurrentWorkerThread::AutoPauseCurrentWorkerThread(ExclusiveContext *cx
                                                            MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 }
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -323,28 +323,28 @@ WorkerThread::maybePause()
         AutoLockWorkerThreadState lock(*runtime->workerThreadState);
         pause();
     }
 }
 
 #endif // JS_WORKER_THREADS
 
 /* Pause any threads that are running jobs off thread during GC activity. */
-class AutoPauseWorkersForGC
+class AutoPauseWorkersForTracing
 {
 #ifdef JS_WORKER_THREADS
     JSRuntime *runtime;
     bool needsUnpause;
     mozilla::DebugOnly<bool> oldExclusiveThreadsPaused;
 #endif
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
-    AutoPauseWorkersForGC(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoPauseWorkersForGC();
+    AutoPauseWorkersForTracing(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+    ~AutoPauseWorkersForTracing();
 };
 
 /*
  * If the current thread is a worker thread, treat it as paused during this
  * class's lifetime. This should be used at any time the current thread is
  * waiting for a worker to complete.
  */
 class AutoPauseCurrentWorkerThread
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -670,17 +670,17 @@ struct MallocProvider
 
 namespace gc {
 class MarkingValidator;
 } // namespace gc
 
 typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
 
 class AutoLockForExclusiveAccess;
-class AutoPauseWorkersForGC;
+class AutoPauseWorkersForTracing;
 class ThreadDataIter;
 
 void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
 
 } // namespace js
 
 struct JSRuntime : public JS::shadow::Runtime,
                    public js::MallocProvider<JSRuntime>
@@ -784,17 +784,17 @@ struct JSRuntime : public JS::shadow::Ru
     mozilla::DebugOnly<PRThread *> exclusiveAccessOwner;
     mozilla::DebugOnly<bool> mainThreadHasExclusiveAccess;
     mozilla::DebugOnly<bool> exclusiveThreadsPaused;
 
     /* Number of non-main threads with an ExclusiveContext. */
     size_t numExclusiveThreads;
 
     friend class js::AutoLockForExclusiveAccess;
-    friend class js::AutoPauseWorkersForGC;
+    friend class js::AutoPauseWorkersForTracing;
     friend class js::ThreadDataIter;
 
   public:
     void setUsedByExclusiveThread(JS::Zone *zone);
     void clearUsedByExclusiveThread(JS::Zone *zone);
 
 #endif // JS_THREADSAFE && JS_ION