Add Debug.prototype.enabled. This implementation is not ideal, since we want clearing .enabled to remove the debugger from every place where it might cause overhead. For now it just sets a flag.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 18 Apr 2011 23:52:17 -0500
changeset 74387 92309cf1aca1be0775b411fe2bb91c0c0edacb89
parent 74386 184ce9343b3955d78636bccccfaee9afada6c3ed
child 74388 7818def1b65b4a23fcb496ce6354fbd9cbc6cc95
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone6.0a1
Add Debug.prototype.enabled. This implementation is not ideal, since we want clearing .enabled to remove the debugger from every place where it might cause overhead. For now it just sets a flag.
js/src/jsdbg.cpp
js/src/jsdbg.h
js/src/tests/js1_8_5/extensions/debug-object-16.js
js/src/tests/js1_8_5/extensions/debug-object-17.js
js/src/tests/js1_8_5/extensions/jstests.list
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -109,17 +109,18 @@ CheckThisClass(JSContext *cx, Value *vp,
         CheckThisClass(cx, vp, &js::classname::jsclass, fnname);             \
     if (!thisobj)                                                            \
         return false;                                                        \
     js::classname *private = (classname *) thisobj->getPrivate();
 
 // === Debug hook dispatch
 
 Debug::Debug(JSObject *dbg, JSObject *hooks, JSCompartment *compartment)
-  : object(dbg), debuggeeCompartment(compartment), hooksObject(hooks), hasDebuggerHandler(false)
+  : object(dbg), debuggeeCompartment(compartment), hooksObject(hooks),
+    enabled(true), hasDebuggerHandler(false)
 {
 }
 
 JSTrapStatus
 Debug::fireUncaughtExceptionHook(JSContext *cx)
 {
     // FIXME
     JS_ReportPendingException(cx);
@@ -343,16 +344,34 @@ Debug::setHooks(JSContext *cx, uintN arg
     dbg->hasDebuggerHandler = !!found;
 
     dbg->hooksObject = hooksobj;
     vp->setUndefined();
     return true;
 }
 
 JSBool
+Debug::getEnabled(JSContext *cx, uintN argc, Value *vp)
+{
+    THISOBJ(cx, vp, Debug, "get enabled", thisobj, dbg);
+    vp->setBoolean(dbg->enabled);
+    return true;
+}
+
+JSBool
+Debug::setEnabled(JSContext *cx, uintN argc, Value *vp)
+{
+    REQUIRE_ARGC("Debug.set enabled", 1);
+    THISOBJ(cx, vp, Debug, "set enabled", thisobj, dbg);
+    dbg->enabled = js_ValueToBoolean(vp[2]);
+    vp->setUndefined();
+    return true;
+}
+
+JSBool
 Debug::construct(JSContext *cx, uintN argc, Value *vp)
 {
     REQUIRE_ARGC("Debug", 1);
 
     // Confirm that the first argument is a cross-compartment wrapper.
     const Value &arg = vp[2];
     if (!arg.isObject())
         return ReportObjectRequired(cx);
@@ -390,16 +409,17 @@ Debug::construct(JSContext *cx, uintN ar
     obj->setPrivate(dbg);
 
     vp->setObject(*obj);
     return true;
 }
 
 JSPropertySpec Debug::properties[] = {
     JS_PSGS("hooks", Debug::getHooks, Debug::setHooks, 0),
+    JS_PSGS("enabled", Debug::getEnabled, Debug::setEnabled, 0),
     JS_PS_END
 };
     
 
 extern JS_PUBLIC_API(JSBool)
 JS_DefineDebugObject(JSContext *cx, JSObject *obj)
 {
     JSObject *objProto;
--- a/js/src/jsdbg.h
+++ b/js/src/jsdbg.h
@@ -52,29 +52,33 @@ namespace js {
 class Debug {
     friend JSBool ::JS_DefineDebugObject(JSContext *cx, JSObject *obj);
 
   private:
     JSObject *object;  // The Debug object. Strong reference.
     JSCompartment *debuggeeCompartment;  // Weak reference.
     JSObject *hooksObject;  // See Debug.prototype.hooks. Strong reference.
 
+    bool enabled;
+
     // True if hooksObject had a debuggerHandler property when the hooks
     // property was set.
     bool hasDebuggerHandler;
 
     JSTrapStatus fireUncaughtExceptionHook(JSContext *cx);
     JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp);
 
     static void trace(JSTracer *trc, JSObject *obj);
     static void finalize(JSContext *cx, JSObject *obj);
 
     static Class jsclass;
     static JSBool getHooks(JSContext *cx, uintN argc, Value *vp);
     static JSBool setHooks(JSContext *cx, uintN argc, Value *vp);
+    static JSBool getEnabled(JSContext *cx, uintN argc, Value *vp);
+    static JSBool setEnabled(JSContext *cx, uintN argc, Value *vp);
     static JSBool construct(JSContext *cx, uintN argc, Value *vp);
     static JSPropertySpec properties[];
 
     bool hasAnyLiveHooks() const { return observesDebuggerStatement(); }
 
   public:
     Debug(JSObject *dbg, JSObject *hooks, JSCompartment *compartment);
 
@@ -104,15 +108,15 @@ class Debug {
         return (Debug *) obj->getPrivate();
     }
 
     bool observesCompartment(JSCompartment *c) const {
         JS_ASSERT(c);
         return debuggeeCompartment == c;
     }
 
-    bool observesDebuggerStatement() const { return hasDebuggerHandler; }
+    bool observesDebuggerStatement() const { return enabled && hasDebuggerHandler; }
     JSTrapStatus onDebuggerStatement(JSContext *cx, Value *vp);
 };
 
 }
 
 #endif /* jsdbg_h__ */
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/debug-object-16.js
@@ -0,0 +1,23 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "enabled");
+assertEq(typeof desc.get, 'function');
+assertEq(typeof desc.set, 'function');
+
+var g = newGlobal('new-compartment');
+var hits;
+var dbg = new Debug(g);
+assertEq(dbg.enabled, true);
+dbg.hooks = {debuggerHandler: function () { hits++; }};
+
+var vals = [true, false, null, undefined, NaN, "blah", {}];
+for (var i = 0; i < vals.length; i++) {
+    dbg.enabled = vals[i];
+    assertEq(dbg.enabled, !!vals[i]);
+    hits = 0;
+    g.eval("debugger;");
+    assertEq(hits, vals[i] ? 1 : 0);
+}
+
+reportCompare(0, 0, 'ok');
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/extensions/debug-object-17.js
@@ -0,0 +1,28 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+// Disabling a Debug object causes events to stop being delivered to it
+// immediately, even if we're in the middle of dispatching.
+
+var g = newGlobal('new-compartment');
+var log;
+
+var arr = [];
+for (var i = 0; i < 4; i++) {
+    arr[i] = new Debug(g);
+    arr[i].hooks = {
+        num: i,
+        debuggerHandler: function () {
+            log += this.num;
+            // Disable them all.
+            for (var j = 0; j < arr.length; j++)
+                arr[j].enabled = false;
+        }
+    };
+}
+
+log = '';
+g.eval("debugger; debugger;");
+assertEq(log, '0');
+
+reportCompare(0, 0, 'ok');
--- a/js/src/tests/js1_8_5/extensions/jstests.list
+++ b/js/src/tests/js1_8_5/extensions/jstests.list
@@ -51,8 +51,10 @@ skip-if(!xulRuntime.shell) script debug-
 skip-if(!xulRuntime.shell) script debug-object-08.js
 skip-if(!xulRuntime.shell) script debug-object-09.js
 skip-if(!xulRuntime.shell) script debug-object-10.js
 skip-if(!xulRuntime.shell) script debug-object-11.js
 skip-if(!xulRuntime.shell) script debug-object-12.js
 skip-if(!xulRuntime.shell) script debug-object-13.js
 skip-if(!xulRuntime.shell) script debug-object-14.js
 skip-if(!xulRuntime.shell) script debug-object-15.js
+skip-if(!xulRuntime.shell) script debug-object-16.js
+skip-if(!xulRuntime.shell) script debug-object-17.js