Bug 1306250 - Iterate gray objects without evicting the nursery r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 14 Oct 2016 09:43:30 +0100
changeset 363095 62817c443347073468fe18e5bde744b9108f8285
parent 363094 679bbfdf2c808f5e3017057edf54c07cb188f938
child 363096 22feffdddcd0d6bade3e267820db292e470f2d1e
push id1369
push userjlorenzo@mozilla.com
push dateMon, 27 Feb 2017 14:59:41 +0000
treeherdermozilla-release@d75a1dba431f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1306250
milestone52.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 1306250 - Iterate gray objects without evicting the nursery r=sfink
js/src/gc/Iteration.cpp
js/src/jsfriendapi.h
js/src/jsgcinlines.h
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -95,29 +95,43 @@ js::IterateScripts(JSContext* cx, JSComp
     } else {
         for (ZonesIter zone(cx, SkipAtoms); !zone.done(); zone.next()) {
             for (auto script = zone->cellIter<JSScript>(empty); !script.done(); script.next())
                 scriptCallback(cx, data, script);
         }
     }
 }
 
+static void
+IterateGrayObjects(Zone* zone, GCThingCallback cellCallback, void* data)
+{
+    for (auto kind : ObjectAllocKinds()) {
+        for (GrayObjectIter obj(zone, kind); !obj.done(); obj.next()) {
+            if (obj->asTenured().isMarked(GRAY))
+                cellCallback(data, JS::GCCellPtr(obj.get()));
+        }
+    }
+}
+
 void
 js::IterateGrayObjects(Zone* zone, GCThingCallback cellCallback, void* data)
 {
     JSRuntime* rt = zone->runtimeFromMainThread();
-    AutoEmptyNursery empty(rt);
+    MOZ_ASSERT(!rt->isHeapBusy());
     AutoPrepareForTracing prep(rt->contextFromMainThread(), SkipAtoms);
+    ::IterateGrayObjects(zone, cellCallback, data);
+}
 
-    for (auto thingKind : ObjectAllocKinds()) {
-        for (auto obj = zone->cellIter<JSObject>(thingKind, empty); !obj.done(); obj.next()) {
-            if (obj->asTenured().isMarked(GRAY))
-                cellCallback(data, JS::GCCellPtr(obj.get()));
-        }
-    }
+void
+js::IterateGrayObjectsUnderCC(Zone* zone, GCThingCallback cellCallback, void* data)
+{
+    JSRuntime* rt = zone->runtimeFromMainThread();
+    MOZ_ASSERT(rt->isCycleCollecting());
+    MOZ_ASSERT(!rt->gc.isIncrementalGCInProgress());
+    ::IterateGrayObjects(zone, cellCallback, data);
 }
 
 JS_PUBLIC_API(void)
 JS_IterateCompartments(JSContext* cx, void* data,
                        JSIterateCompartmentCallback compartmentCallback)
 {
     AutoTraceSession session(cx);
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -518,21 +518,28 @@ typedef void
 
 extern JS_FRIEND_API(void)
 VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure);
 
 extern JS_FRIEND_API(JSObject*)
 GetWeakmapKeyDelegate(JSObject* key);
 
 /**
- * Invoke cellCallback on every gray JS_OBJECT in the given zone.
+ * Invoke cellCallback on every gray JSObject in the given zone.
  */
 extern JS_FRIEND_API(void)
 IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data);
 
+/**
+ * Invoke cellCallback on every gray JSObject in the given zone while cycle
+ * collection is in progress.
+ */
+extern JS_FRIEND_API(void)
+IterateGrayObjectsUnderCC(JS::Zone* zone, GCThingCallback cellCallback, void* data);
+
 #ifdef JS_HAS_CTYPES
 extern JS_FRIEND_API(size_t)
 SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj);
 #endif
 
 extern JS_FRIEND_API(JSCompartment*)
 GetAnyCompartmentInZone(JS::Zone* zone);
 
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -204,19 +204,23 @@ class ZoneCellIter<TenuredCell> {
     ArenaCellIterImpl cellIter;
     JS::AutoAssertNoAlloc noAlloc;
 
   protected:
     // For use when a subclass wants to insert some setup before init().
     ZoneCellIter() {}
 
     void init(JS::Zone* zone, AllocKind kind) {
+        MOZ_ASSERT_IF(IsNurseryAllocable(kind),
+                      zone->runtimeFromAnyThread()->gc.nursery.isEmpty());
+        initForTenuredIteration(zone, kind);
+    }
+
+    void initForTenuredIteration(JS::Zone* zone, AllocKind kind) {
         JSRuntime* rt = zone->runtimeFromAnyThread();
-        MOZ_ASSERT(zone);
-        MOZ_ASSERT_IF(IsNurseryAllocable(kind), rt->gc.nursery.isEmpty());
 
         // If called from outside a GC, ensure that the heap is in a state
         // that allows us to iterate.
         if (!rt->isHeapBusy()) {
             // Assert that no GCs can occur while a ZoneCellIter is live.
             noAlloc.disallowAlloc(rt);
         }
 
@@ -341,16 +345,27 @@ class ZoneCellIter : public ZoneCellIter
     {
     }
 
     GCType* get() const { return ZoneCellIter<TenuredCell>::get<GCType>(); }
     operator GCType*() const { return get(); }
     GCType* operator ->() const { return get(); }
 };
 
+class GrayObjectIter : public ZoneCellIter<TenuredCell> {
+  public:
+    explicit GrayObjectIter(JS::Zone* zone, AllocKind kind) : ZoneCellIter<TenuredCell>() {
+        initForTenuredIteration(zone, kind);
+    }
+
+    JSObject* get() const { return ZoneCellIter<TenuredCell>::get<JSObject>(); }
+    operator JSObject*() const { return get(); }
+    JSObject* operator ->() const { return get(); }
+};
+
 class GCZonesIter
 {
   private:
     ZonesIter zone;
 
   public:
     explicit GCZonesIter(JSRuntime* rt, ZoneSelector selector = WithAtoms) : zone(rt, selector) {
         if (!zone->isCollecting())