Bug 1232229 - Add assertions to prevent nursery allocation when setting up OMT parse tasks r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 25 Feb 2016 09:43:06 +0000
changeset 321891 17bfd6a2a52944f0f0e544dcc5e9d8118dd46d02
parent 321890 244ab4103b969298cc006d1459de0653344235dd
child 321892 5a5874ed903337de47dff5c76ed7cf541e3f3788
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1232229
milestone47.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 1232229 - Add assertions to prevent nursery allocation when setting up OMT parse tasks r=terrence
js/src/gc/Allocator.cpp
js/src/gc/GCRuntime.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/vm/HelperThreads.cpp
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -145,16 +145,18 @@ template JSObject* js::Allocate<JSObject
                                                  const Class* clasp);
 
 // Attempt to allocate a new GC thing out of the nursery. If there is not enough
 // room in the nursery or there is an OOM, this method will return nullptr.
 template <AllowGC allowGC>
 JSObject*
 GCRuntime::tryNewNurseryObject(JSContext* cx, size_t thingSize, size_t nDynamicSlots, const Class* clasp)
 {
+    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);
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -703,16 +703,23 @@ class GCRuntime
 #ifdef DEBUG
     bool isAllocAllowed() { return noGCOrAllocationCheck == 0; }
     void disallowAlloc() { ++noGCOrAllocationCheck; }
     void allowAlloc() {
         MOZ_ASSERT(!isAllocAllowed());
         --noGCOrAllocationCheck;
     }
 
+    bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; }
+    void disallowNurseryAlloc() { ++noNurseryAllocationCheck; }
+    void allowNurseryAlloc() {
+        MOZ_ASSERT(!isNurseryAllocAllowed());
+        --noNurseryAllocationCheck;
+    }
+
     bool isInsideUnsafeRegion() { return inUnsafeRegion != 0; }
     void enterUnsafeRegion() { ++inUnsafeRegion; }
     void leaveUnsafeRegion() {
         MOZ_ASSERT(inUnsafeRegion > 0);
         --inUnsafeRegion;
     }
 
     bool isStrictProxyCheckingEnabled() { return disableStrictProxyCheckingCount == 0; }
@@ -1307,16 +1314,17 @@ class GCRuntime
      * Some regions of code are hard for the static rooting hazard analysis to
      * understand. In those cases, we trade the static analysis for a dynamic
      * analysis. When this is non-zero, we should assert if we trigger, or
      * might trigger, a GC.
      */
     int inUnsafeRegion;
 
     size_t noGCOrAllocationCheck;
+    size_t noNurseryAllocationCheck;
 #endif
 
     /* Synchronize GC heap access between main thread and GCHelperState. */
     PRLock* lock;
     mozilla::DebugOnly<mozilla::Atomic<PRThread*>> lockOwner;
 
     BackgroundAllocTask allocTask;
     GCHelperState helperState;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1213,16 +1213,17 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
 #endif
     fullCompartmentChecks(false),
     mallocBytesUntilGC(0),
     mallocGCTriggered(false),
     alwaysPreserveCode(false),
 #ifdef DEBUG
     inUnsafeRegion(0),
     noGCOrAllocationCheck(0),
+    noNurseryAllocationCheck(0),
 #endif
     lock(nullptr),
     allocTask(rt, emptyChunks_),
     helperState(rt)
 {
     setGCMode(JSGC_MODE_GLOBAL);
 }
 
@@ -7352,16 +7353,27 @@ void JS::AutoAssertNoAlloc::disallowAllo
     gc->disallowAlloc();
 }
 
 JS::AutoAssertNoAlloc::~AutoAssertNoAlloc()
 {
     if (gc)
         gc->allowAlloc();
 }
+
+AutoAssertNoNurseryAlloc::AutoAssertNoNurseryAlloc(JSRuntime* rt)
+  : gc(rt->gc)
+{
+    gc.disallowNurseryAlloc();
+}
+
+AutoAssertNoNurseryAlloc::~AutoAssertNoNurseryAlloc()
+{
+    gc.allowNurseryAlloc();
+}
 #endif
 
 JS::AutoAssertGCCallback::AutoAssertGCCallback(JSObject* obj)
   : AutoSuppressGCAnalysis()
 {
     MOZ_ASSERT(obj->runtimeFromMainThread()->isHeapCollecting());
 }
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1349,16 +1349,29 @@ class ZoneList
 
     ZoneList(const ZoneList& other) = delete;
     ZoneList& operator=(const ZoneList& other) = delete;
 };
 
 JSObject*
 NewMemoryStatisticsObject(JSContext* cx);
 
+struct MOZ_RAII AutoAssertNoNurseryAlloc
+{
+#ifdef DEBUG
+    explicit AutoAssertNoNurseryAlloc(JSRuntime* rt);
+    ~AutoAssertNoNurseryAlloc();
+
+  private:
+    gc::GCRuntime& gc;
+#else
+    explicit AutoAssertNoNurseryAlloc(JSRuntime* rt) {}
+#endif
+};
+
 } /* namespace gc */
 
 #ifdef DEBUG
 /* Use this to avoid assertions when manipulating the wrapper map. */
 class MOZ_RAII AutoDisableProxyCheck
 {
     gc::GCRuntime& gc;
 
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -455,16 +455,17 @@ QueueOffThreadParseTask(JSContext* cx, P
 bool
 js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                               const char16_t* chars, size_t length,
                               JS::OffThreadCompileCallback callback, void* callbackData)
 {
     // Suppress GC so that calls below do not trigger a new incremental GC
     // which could require barriers on the atoms compartment.
     gc::AutoSuppressGC nogc(cx);
+    gc::AutoAssertNoNurseryAlloc noNurseryAlloc(cx->runtime());
 
     JSObject* global = CreateGlobalForOffThreadParse(cx, ParseTaskKind::Script, nogc);
     if (!global)
         return false;
 
     ScopedJSDeletePtr<ExclusiveContext> helpercx(
         cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData*) nullptr,
                                    ExclusiveContext::Context_Exclusive));