Bug 1519037 - Filter out objects that is about to be finalized when iterating for non-GC purpose. r=pbone a=lizzard
authorTooru Fujisawa <arai_a@mac.com>
Fri, 08 Feb 2019 02:39:12 +0000
changeset 515881 733e8bfd0ba3743941128235f388af561fda3cea
parent 515880 4967e7f39711308ee2e7f1b7d9420c5148d43d95
child 515882 49a04a5d8d979f1d8b90352c675d22a91f17fcdb
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbone, lizzard
bugs1519037
milestone66.0
Bug 1519037 - Filter out objects that is about to be finalized when iterating for non-GC purpose. r=pbone a=lizzard Differential Revision: https://phabricator.services.mozilla.com/D18845
js/src/gc/GC-inl.h
js/src/gc/PublicIterators.cpp
js/src/jit/BaselineJIT.cpp
js/src/vm/BytecodeUtil.cpp
js/src/vm/Debugger.cpp
js/src/vm/Realm.cpp
--- a/js/src/gc/GC-inl.h
+++ b/js/src/gc/GC-inl.h
@@ -316,16 +316,19 @@ class ZoneCellIter<TenuredCell> {
 // remove themselves from the store buffer on deletion, but currently for
 // subtle reasons that isn't good enough.)
 //
 // If the iterator is used within a GC, then there is no need to evict the
 // nursery (again). You may select a variant that will skip the eviction either
 // by specializing on a GCType that is never allocated in the nursery, or
 // explicitly by passing in a trailing AutoAssertEmptyNursery argument.
 //
+// NOTE: This class can return items that are about to be swept/finalized.
+//       You shouldn't keep pointers to such items across GCs.
+//
 /* clang-format on */
 template <typename GCType>
 class ZoneCellIter : public ZoneCellIter<TenuredCell> {
  public:
   // Non-nursery allocated (equivalent to having an entry in
   // MapTypeToFinalizeKind). The template declaration here is to discard this
   // constructor overload if MapTypeToFinalizeKind<GCType>::kind does not
   // exist. Note that there will be no remaining overloads that will work,
--- a/js/src/gc/PublicIterators.cpp
+++ b/js/src/gc/PublicIterators.cpp
@@ -150,26 +150,33 @@ static void IterateScriptsImpl(JSContext
                                Callback scriptCallback) {
   MOZ_ASSERT(!cx->suppressGC);
   AutoEmptyNursery empty(cx);
   AutoPrepareForTracing prep(cx);
   JS::AutoSuppressGCAnalysis nogc;
 
   if (realm) {
     Zone* zone = realm->zone();
-    for (auto script = zone->cellIter<T>(empty); !script.done();
-         script.next()) {
-      if (script->realm() == realm) {
-        DoScriptCallback(cx, data, script, scriptCallback, nogc);
+    for (auto iter = zone->cellIter<T>(empty); !iter.done(); iter.next()) {
+      T* script = iter;
+      if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        continue;
       }
+      if (script->realm() != realm) {
+        continue;
+      }
+      DoScriptCallback(cx, data, script, scriptCallback, nogc);
     }
   } else {
     for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
-      for (auto script = zone->cellIter<T>(empty); !script.done();
-           script.next()) {
+      for (auto iter = zone->cellIter<T>(empty); !iter.done(); iter.next()) {
+        T* script = iter;
+        if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+          continue;
+        }
         DoScriptCallback(cx, data, script, scriptCallback, nogc);
       }
     }
   }
 }
 
 void js::IterateScripts(JSContext* cx, Realm* realm, void* data,
                         IterateScriptCallback scriptCallback) {
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -1174,44 +1174,53 @@ void jit::AddSizeOfBaselineData(JSScript
 
 void jit::ToggleBaselineProfiling(JSRuntime* runtime, bool enable) {
   JitRuntime* jrt = runtime->jitRuntime();
   if (!jrt) {
     return;
   }
 
   for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
-    for (auto script = zone->cellIter<JSScript>(); !script.done();
-         script.next()) {
+    for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+      JSScript* script = iter;
+      if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        continue;
+      }
       if (!script->hasBaselineScript()) {
         continue;
       }
       AutoWritableJitCode awjc(script->baselineScript()->method());
       script->baselineScript()->toggleProfilerInstrumentation(enable);
     }
   }
 }
 
 #ifdef JS_TRACE_LOGGING
 void jit::ToggleBaselineTraceLoggerScripts(JSRuntime* runtime, bool enable) {
   for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
-    for (auto script = zone->cellIter<JSScript>(); !script.done();
-         script.next()) {
+    for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+      JSScript* script = iter;
+      if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        continue;
+      }
       if (!script->hasBaselineScript()) {
         continue;
       }
       script->baselineScript()->toggleTraceLoggerScripts(script, enable);
     }
   }
 }
 
 void jit::ToggleBaselineTraceLoggerEngine(JSRuntime* runtime, bool enable) {
   for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
-    for (auto script = zone->cellIter<JSScript>(); !script.done();
-         script.next()) {
+    for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+      JSScript* script = iter;
+      if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        continue;
+      }
       if (!script->hasBaselineScript()) {
         continue;
       }
       script->baselineScript()->toggleTraceLoggerEngine(enable);
     }
   }
 }
 #endif
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -177,16 +177,19 @@ static MOZ_MUST_USE bool DumpPCCounts(JS
   return true;
 }
 
 bool js::DumpRealmPCCounts(JSContext* cx) {
   Rooted<GCVector<JSScript*>> scripts(cx, GCVector<JSScript*>(cx));
   for (auto iter = cx->zone()->cellIter<JSScript>(); !iter.done();
        iter.next()) {
     JSScript* script = iter;
+    if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+      continue;
+    }
     if (script->realm() != cx->realm()) {
       continue;
     }
     if (script->hasScriptCounts()) {
       if (!scripts.append(script)) {
         return false;
       }
     }
@@ -2524,18 +2527,21 @@ JS_FRIEND_API void js::StopPCCountProfil
 
   auto* vec = cx->new_<PersistentRooted<ScriptAndCountsVector>>(
       cx, ScriptAndCountsVector(SystemAllocPolicy()));
   if (!vec) {
     return;
   }
 
   for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
-    for (auto script = zone->cellIter<JSScript>(); !script.done();
-         script.next()) {
+    for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+      JSScript* script = iter;
+      if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        continue;
+      }
       AutoSweepTypeScript sweep(script);
       if (script->hasScriptCounts() && script->types(sweep)) {
         if (!vec->append(script)) {
           return;
         }
       }
     }
   }
@@ -2825,18 +2831,21 @@ static bool GenerateLcovInfo(JSContext* 
 
   // Hold the scripts that we have already flushed, to avoid flushing them
   // twice.
   using JSScriptSet = GCHashSet<JSScript*>;
   Rooted<JSScriptSet> scriptsDone(cx, JSScriptSet(cx));
 
   Rooted<ScriptVector> queue(cx, ScriptVector(cx));
   for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
-    for (auto script = zone->cellIter<JSScript>(); !script.done();
-         script.next()) {
+    for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
+      JSScript* script = iter;
+      if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        continue;
+      }
       if (script->realm() != realm || !script->filename()) {
         continue;
       }
 
       if (!queue.append(script)) {
         return false;
       }
     }
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2743,18 +2743,20 @@ static bool UpdateExecutionObservability
       if (obs.shouldRecompileOrInvalidate(script)) {
         if (!AppendAndInvalidateScript(cx, zone, script, scripts)) {
           return false;
         }
       }
     } else {
       for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
         JSScript* script = iter;
-        if (obs.shouldRecompileOrInvalidate(script) &&
-            !gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+        if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+          continue;
+        }
+        if (obs.shouldRecompileOrInvalidate(script)) {
           if (!AppendAndInvalidateScript(cx, zone, script, scripts)) {
             return false;
           }
         }
       }
     }
   }
 
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -880,18 +880,21 @@ void Realm::clearScriptCounts() {
 
   scriptCountsMap.reset();
 }
 
 void Realm::clearScriptNames() { scriptNameMap.reset(); }
 
 void Realm::clearBreakpointsIn(FreeOp* fop, js::Debugger* dbg,
                                HandleObject handler) {
-  for (auto script = zone()->cellIter<JSScript>(); !script.done();
-       script.next()) {
+  for (auto iter = zone()->cellIter<JSScript>(); !iter.done(); iter.next()) {
+    JSScript* script = iter;
+    if (gc::IsAboutToBeFinalizedUnbarriered(&script)) {
+      continue;
+    }
     if (script->realm() == this && script->hasAnyBreakpointsOrStepMode()) {
       script->clearBreakpointsIn(fop, dbg, handler);
     }
   }
 }
 
 void ObjectRealm::addSizeOfExcludingThis(
     mozilla::MallocSizeOf mallocSizeOf, size_t* innerViewsArg,