diff --git a/js/src/jit-test/tests/debug/gc-03.js b/js/src/jit-test/tests/debug/gc-03.js new file mode 100644 index 00000000000..d6e1d57e198 --- /dev/null +++ b/js/src/jit-test/tests/debug/gc-03.js @@ -0,0 +1,27 @@ +// |jit-test| debug +// Storing a property on a Debug.Object protects it from GC as long as the +// referent is alive. + +var g = newGlobal('new-compartment'); +var N = g.N = 3; +var dbg = Debug(g); + +var i = 0; +dbg.hooks = { + debuggerHandler: function (frame) { + frame.arguments[0].id = i++; + } +}; +g.eval("function f(x) { debugger; }"); +g.eval("var arr = [], j; for (j = 0; j < N; j++) arr[j] = {};"); +g.eval("for (j = 0; j < N; j++) f(arr[j]);"); +assertEq(i, N); + +gc(); gc(); + +i = 0; +dbg.hooks.debuggerHandler = function (frame) { + assertEq(frame.arguments[0].id, i++) +} +g.eval("for (j = 0; j < N; j++) f(arr[j]);"); +assertEq(i, N); diff --git a/js/src/jit-test/tests/debug/gc-04.js b/js/src/jit-test/tests/debug/gc-04.js new file mode 100644 index 00000000000..8ea9a6f6d15 --- /dev/null +++ b/js/src/jit-test/tests/debug/gc-04.js @@ -0,0 +1,28 @@ +// |jit-test| debug +// Storing a Debug.Object as a key in a WeakMap protects it from GC as long as +// the referent is alive. + +var g = newGlobal('new-compartment'); +var N = g.N = 10; +var dbg = Debug(g); +var cache = new WeakMap; + +var i = 0; +dbg.hooks = { + debuggerHandler: function (frame) { + cache.set(frame.arguments[0], i++); + } +}; +g.eval("function f(x) { debugger; }"); +g.eval("var arr = [], j; for (j = 0; j < N; j++) arr[j] = {};"); +g.eval("for (j = 0; j < N; j++) f(arr[j]);"); +assertEq(i, N); + +gc(); gc(); + +i = 0; +dbg.hooks.debuggerHandler = function (frame) { + assertEq(cache.get(frame.arguments[0]), i++) +}; +g.eval("for (j = 0; j < N; j++) f(arr[j]);"); +assertEq(i, N); diff --git a/js/src/jsdbg.cpp b/js/src/jsdbg.cpp index 3e2f34d395a..90cd41703e6 100644 --- a/js/src/jsdbg.cpp +++ b/js/src/jsdbg.cpp @@ -483,8 +483,13 @@ Debug::mark(GCMarker *trc, JSCompartment *comp, JSGCInvocationKind gckind) // if (!comp || obj->compartment() == comp) { for (ObjectMap::Range r = dbg->objects.all(); !r.empty(); r.popFront()) { - if (!r.front().value->isMarked() && (comp || r.front().key->isMarked())) { - MarkObject(trc, *r.front().key, "Debug.Object with live referent"); + // The unwrap() call below has the following effect: we + // mark the Debug.Object if the *referent* is alive, + // even if the CCW of the referent seems unreachable. + if (!r.front().value->isMarked() && + (comp || r.front().key->unwrap()->isMarked())) + { + MarkObject(trc, *r.front().value, "Debug.Object with live referent"); markedAny = true; } }