GlobalObject::getOrCreateDebuggers must be called in the global object's compartment, since it may create an object.
GlobalObject::getOrCreateDebuggers must be called in the global object's compartment, since it may create an object.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/gc-compartment-01.js
@@ -0,0 +1,6 @@
+// A debugger can survive per-compartment GC.
+
+var g = newGlobal('new-compartment');
+var dbg = Debug(g);
+gc(g);
+gc(this);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/gc-compartment-02.js
@@ -0,0 +1,13 @@
+// Referents of Debug.Objects in other compartments always survive per-compartment GC.
+
+var g = newGlobal('new-compartment');
+var dbg = Debug(g);
+var arr = [];
+dbg.hooks = {debuggerHandler: function (frame) { arr.push(frame.eval("[]").return); }};
+g.eval("for (var i = 0; i < 10; i++) debugger;");
+assertEq(arr.length, 10);
+
+gc(g);
+
+for (var i = 0; i < arr.length; i++)
+ assertEq(arr[i].class, "Array");
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -957,16 +957,19 @@ Debug::addDebuggeeGlobal(JSContext *cx,
if (visited.find(next) == visited.end() && !visited.append(next))
return false;
}
}
}
// Each debugger-debuggee relation must be stored in up to three places.
// JSCompartment::addDebuggee enables debug mode if needed.
+ AutoCompartment ac(cx, obj);
+ if (!ac.enter())
+ return false;
GlobalObject::DebugVector *v = obj->getOrCreateDebuggers(cx);
if (!v || !v->append(this)) {
js_ReportOutOfMemory(cx);
goto fail1;
}
if (!debuggees.put(obj)) {
js_ReportOutOfMemory(cx);
goto fail2;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -222,16 +222,17 @@ GlobalObject::getDebuggers()
return NULL;
JS_ASSERT(debuggers.toObject().clasp == &GlobalDebuggees_class);
return (DebugVector *) debuggers.toObject().getPrivate();
}
GlobalObject::DebugVector *
GlobalObject::getOrCreateDebuggers(JSContext *cx)
{
+ assertSameCompartment(cx, this);
DebugVector *vec = getDebuggers();
if (vec)
return vec;
JSObject *obj = NewNonFunction<WithProto::Given>(cx, &GlobalDebuggees_class, NULL, NULL);
if (!obj)
return NULL;
vec = cx->new_<DebugVector>();