Bug 1136597 - Mark all relevant cross compartment debugger edges when sweeping r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 04 Mar 2015 14:45:19 +0000
changeset 231886 50913131140c0f2c3d938df886745082192d44ef
parent 231885 a190978e94f12f56dcf492269d606c7bdd7af978
child 231887 796e84a25f163f691e0b44ad2359ff3660303eb0
push id28362
push userryanvm@gmail.com
push dateWed, 04 Mar 2015 21:35:51 +0000
treeherdermozilla-central@56492f7244a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1136597
milestone39.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 1136597 - Mark all relevant cross compartment debugger edges when sweeping r=terrence
js/src/gc/RootMarking.cpp
js/src/jit-test/tests/gc/bug-1136597.js
js/src/jsgc.cpp
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -425,17 +425,17 @@ js::gc::GCRuntime::markRuntime(JSTracer 
 
     if (traceOrMark == MarkRuntime) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_CCWS);
 
         for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
             if (!c->zone()->isCollecting())
                 c->markCrossCompartmentWrappers(trc);
         }
-        Debugger::markAllCrossCompartmentEdges(trc);
+        Debugger::markIncomingCrossCompartmentEdges(trc);
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTERS);
 
         AutoGCRooter::traceAll(trc);
 
         if (!rt->isBeingDestroyed()) {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1136597.js
@@ -0,0 +1,24 @@
+// |jit-test| error:ReferenceError
+var evalInFrame = (function (global) {
+  var dbgGlobal = newGlobal();
+  var dbg = new dbgGlobal.Debugger();
+  return function evalInFrame(upCount, code) {
+    dbg.addDebuggee(global);
+  };
+})(this);
+var gTestcases = new Array();
+var gTc = gTestcases.length;
+function TestCase()
+  gTestcases[gTc++] = this;
+function checkCollation(extensionCoValue, usageValue) {
+    var collator = new Intl.Collator(["de-DE"]);
+    collator.resolvedOptions().collation;
+}
+checkCollation(undefined, "sort");
+checkCollation();
+for ( addpow = 0; addpow < 33; addpow++ ) {
+    new TestCase();
+}
+evalInFrame(0, "i(true)", true);
+gc(3, 'shrinking')
+eval("gc(); h = g1");
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2627,17 +2627,17 @@ GCRuntime::updatePointersToRelocatedCell
         updateAllCellPointersSerial(&trc);
 
     // Mark roots to update them.
     {
         markRuntime(&trc, MarkRuntime);
 
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS);
         Debugger::markAll(&trc);
-        Debugger::markAllCrossCompartmentEdges(&trc);
+        Debugger::markIncomingCrossCompartmentEdges(&trc);
 
         for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
             WeakMapBase::markAll(c, &trc);
             if (c->watchpointMap)
                 c->watchpointMap->markAll(&trc);
         }
 
         // Mark all gray roots, making sure we call the trace callback to get the
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2108,25 +2108,34 @@ Debugger::markCrossCompartmentEdges(JSTr
  * to mark the keys and the private pointer in the wrapper object.
  *
  * We must scan all Debugger objects regardless of whether they *currently* have
  * any debuggees in a compartment being GC'd, because the WeakMap entries
  * persist even when debuggees are removed.
  *
  * This happens during the initial mark phase, not iterative marking, because
  * all the edges being reported here are strong references.
+ *
+ * This method is also used during compacting GC to update cross compartment
+ * pointers in zones that are not currently being compacted.
  */
 /* static */ void
-Debugger::markAllCrossCompartmentEdges(JSTracer *trc)
+Debugger::markIncomingCrossCompartmentEdges(JSTracer *trc)
 {
     JSRuntime *rt = trc->runtime();
+    gc::State state = rt->gc.state();
+    MOZ_ASSERT(state == gc::MARK_ROOTS || state == gc::COMPACT);
 
     for (Debugger *dbg = rt->debuggerList.getFirst(); dbg; dbg = dbg->getNext()) {
-        if (!dbg->object->zone()->isCollecting())
+        Zone *zone = dbg->object->zone();
+        if ((state == gc::MARK_ROOTS && !zone->isCollecting()) ||
+            (state == gc::COMPACT && !zone->isGCCompacting()))
+        {
             dbg->markCrossCompartmentEdges(trc);
+        }
     }
 }
 
 /*
  * This method has two tasks:
  *   1. Mark Debugger objects that are unreachable except for debugger hooks that
  *      may yet be called.
  *   2. Mark breakpoint handlers.
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -559,17 +559,17 @@ class Debugger : private mozilla::Linked
      *       - it has a debugger hook installed
      *       - it has a breakpoint set on a live script
      *       - it has a watchpoint set on a live object.
      *
      * Debugger::markAllIteratively handles the last case. If it finds any
      * Debugger objects that are definitely live but not yet marked, it marks
      * them and returns true. If not, it returns false.
      */
-    static void markAllCrossCompartmentEdges(JSTracer *tracer);
+    static void markIncomingCrossCompartmentEdges(JSTracer *tracer);
     static bool markAllIteratively(GCMarker *trc);
     static void markAll(JSTracer *trc);
     static void sweepAll(FreeOp *fop);
     static void detachAllDebuggersFromGlobal(FreeOp *fop, GlobalObject *global);
     static void findCompartmentEdges(JS::Zone *v, gc::ComponentFinder<JS::Zone> &finder);
 
     /*
      * JSTrapStatus Overview