New rule: a Debug object cannot be attached to a compartment that is not in debug mode. Includes a jsapi-test to check that we do not crash if you turn debug mode off while a Debug object is already attached. (This changeset moves all the Debug object tests under jit-tests because the jit-test runner lets tests ask for debug mode.)

--HG--
rename : js/src/tests/js1_8_5/extensions/debug-object-01.js => js/src/jit-test/tests/debug/debug-object-01.js
rename : js/src/tests/js1_8_5/extensions/debug-object-02.js => js/src/jit-test/tests/debug/debug-object-02.js
rename : js/src/tests/js1_8_5/extensions/debug-object-03.js => js/src/jit-test/tests/debug/debug-object-03.js
rename : js/src/tests/js1_8_5/extensions/debug-object-04.js => js/src/jit-test/tests/debug/debug-object-04.js
rename : js/src/tests/js1_8_5/extensions/debug-object-05.js => js/src/jit-test/tests/debug/debug-object-05.js
rename : js/src/tests/js1_8_5/extensions/debug-object-06.js => js/src/jit-test/tests/debug/debug-object-06.js
rename : js/src/tests/js1_8_5/extensions/debug-object-07.js => js/src/jit-test/tests/debug/debug-object-07.js
rename : js/src/tests/js1_8_5/extensions/debug-object-08.js => js/src/jit-test/tests/debug/debug-object-08.js
rename : js/src/tests/js1_8_5/extensions/debug-object-09.js => js/src/jit-test/tests/debug/debug-object-09.js
rename : js/src/tests/js1_8_5/extensions/debug-object-10.js => js/src/jit-test/tests/debug/debug-object-10.js
rename : js/src/tests/js1_8_5/extensions/debug-object-11.js => js/src/jit-test/tests/debug/debug-object-11.js
rename : js/src/tests/js1_8_5/extensions/debug-object-12.js => js/src/jit-test/tests/debug/debug-object-12.js
rename : js/src/tests/js1_8_5/extensions/debug-object-13.js => js/src/jit-test/tests/debug/debug-object-13.js
rename : js/src/tests/js1_8_5/extensions/debug-object-14.js => js/src/jit-test/tests/debug/debug-object-14.js
rename : js/src/tests/js1_8_5/extensions/debug-object-15.js => js/src/jit-test/tests/debug/debug-object-15.js
rename : js/src/tests/js1_8_5/extensions/debug-object-16.js => js/src/jit-test/tests/debug/debug-object-16.js
rename : js/src/tests/js1_8_5/extensions/debug-object-17.js => js/src/jit-test/tests/debug/debug-object-17.js
rename : js/src/tests/js1_8_5/extensions/debug-object-18.js => js/src/jit-test/tests/debug/debug-object-18.js
rename : js/src/tests/js1_8_5/extensions/debug-object-19.js => js/src/jit-test/tests/debug/debug-object-19.js
rename : js/src/tests/js1_8_5/extensions/debug-object-20.js => js/src/jit-test/tests/debug/debug-object-20.js
rename : js/src/tests/js1_8_5/extensions/debug-object-21.js => js/src/jit-test/tests/debug/debug-object-21.js
This commit is contained in:
Jason Orendorff 2011-04-27 17:37:14 -05:00
parent a39d2d024a
commit 4fcb55d0aa
34 changed files with 237 additions and 245 deletions

View File

@ -52,7 +52,7 @@ The general format in EBNF is:
cookie ::= "|jit-test|" cookie ::= "|jit-test|"
item ::= flag | attribute item ::= flag | attribute
flag ::= "slow" | "allow-oom" flag ::= "slow" | "allow-oom" | "valgrind" | "mjitalways" | "debug"
attribute ::= name ":" value attribute ::= name ":" value
name ::= "TMFLAGS" | "error" name ::= "TMFLAGS" | "error"
@ -66,6 +66,8 @@ The meaning of the items:
slow Test runs slowly. Do not run if the --no-slow option is given. slow Test runs slowly. Do not run if the --no-slow option is given.
allow-oom If the test runs out of memory, it counts as passing. allow-oom If the test runs out of memory, it counts as passing.
valgrind Run test under valgrind. valgrind Run test under valgrind.
mjitalways Run js with -a, whether --jitflags says to or not
debug Run js with -d, whether --jitflags says to or not
error The test should be considered to pass iff it throws the error The test should be considered to pass iff it throws the
given JS exception. given JS exception.

View File

@ -0,0 +1,36 @@
if (typeof assertThrowsInstanceOf === 'undefined') {
var assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {
var fullmsg;
try {
f();
} catch (exc) {
if (exc instanceof ctor)
return;
fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
}
if (fullmsg === undefined)
fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
if (msg !== undefined)
fullmsg += " - " + msg;
throw new Error(fullmsg);
};
}
if (typeof assertThrowsValue === 'undefined') {
var assertThrowsValue = function assertThrowsValue(f, val, msg) {
var fullmsg;
try {
f();
} catch (exc) {
if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
return;
fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
}
if (fullmsg === undefined)
fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
if (msg !== undefined)
fullmsg += " - " + msg;
throw new Error(fullmsg);
};
}

View File

@ -0,0 +1,17 @@
// |jit-test| debug
function checkFunction(obj, name, nargs) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
assertEq(desc.configurable, true, name + " should be configurable");
assertEq(desc.writable, true, name + " should be writable");
assertEq(desc.enumerable, false, name + " should be non-enumerable");
assertEq(desc.value, obj[name]); // well obviously
assertEq(typeof desc.value, 'function', name + " should be a function");
assertEq(desc.value.length, nargs, name + " should have .length === " + nargs);
}
checkFunction(this, "Debug", 1);
assertEq(Debug.prototype.constructor, Debug);
assertEq(Object.prototype.toString.call(Debug.prototype), "[object Debug]");
assertEq(Object.getPrototypeOf(Debug.prototype), Object.prototype);

View File

@ -0,0 +1,36 @@
// |jit-test| debug
load(libdir + 'asserts.js');
// Debug rejects arguments that aren't cross-compartment wrappers.
assertThrowsInstanceOf(function () { Debug(); }, TypeError);
assertThrowsInstanceOf(function () { Debug(null); }, TypeError);
assertThrowsInstanceOf(function () { Debug(true); }, TypeError);
assertThrowsInstanceOf(function () { Debug(42); }, TypeError);
assertThrowsInstanceOf(function () { Debug("bad"); }, TypeError);
assertThrowsInstanceOf(function () { Debug(function () {}); }, TypeError);
assertThrowsInstanceOf(function () { Debug(this); }, TypeError);
assertThrowsInstanceOf(function () { new Debug(); }, TypeError);
assertThrowsInstanceOf(function () { new Debug(null); }, TypeError);
assertThrowsInstanceOf(function () { new Debug(true); }, TypeError);
assertThrowsInstanceOf(function () { new Debug(42); }, TypeError);
assertThrowsInstanceOf(function () { new Debug("bad"); }, TypeError);
assertThrowsInstanceOf(function () { new Debug(function () {}); }, TypeError);
assertThrowsInstanceOf(function () { new Debug(this); }, TypeError);
// Very basic tests of Debug creation.
var g = newGlobal('new-compartment');
var dbg = new Debug(g);
assertEq(dbg instanceof Debug, true);
assertEq(Object.getPrototypeOf(dbg), Debug.prototype);
// The reverse.
var g2 = newGlobal('new-compartment');
g2.debuggeeGlobal = this;
g2.eval("var dbg = new Debug(debuggeeGlobal);");
assertEq(g2.eval("dbg instanceof Debug"), true);
// The Debug constructor from this compartment will not accept as its argument
// an Object from this compartment. Shenanigans won't fool the membrane.
g2.outer = this;
assertThrowsInstanceOf(function () { g2.eval("outer.Debug(outer.Object())"); }, TypeError);

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.log = ''; g.log = '';
@ -14,5 +12,3 @@ dbg.hooks = hooks;
assertEq(dbg.hooks, hooks); assertEq(dbg.hooks, hooks);
assertEq(g.eval("log += '1'; debugger; log += '2'; 3;"), 3); assertEq(g.eval("log += '1'; debugger; log += '2'; 3;"), 3);
assertEq(g.log, '1!2'); assertEq(g.log, '1!2');
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Activity in the debugger compartment should not trigger debug hooks. // Activity in the debugger compartment should not trigger debug hooks.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
@ -27,5 +25,3 @@ assertEq(hit, false, "debugger statement in debugger compartment eval code shoul
var g2 = newGlobal('new-compartment'); var g2 = newGlobal('new-compartment');
g2.eval("debugger;"); g2.eval("debugger;");
assertEq(hit, false, "debugger statement in unrelated non-debuggee compartment should not hit"); assertEq(hit, false, "debugger statement in unrelated non-debuggee compartment should not hit");
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// A debugger statement in a debuggerHandler should not reenter. // A debugger statement in a debuggerHandler should not reenter.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
@ -16,5 +14,3 @@ dbg.hooks = {
assertEq(g.eval("debugger; 7;"), 7); assertEq(g.eval("debugger; 7;"), 7);
assertEq(calls, 1); assertEq(calls, 1);
reportCompare(0, 0, 'ok');

View File

@ -0,0 +1,18 @@
// |jit-test| debug
// Simple {throw:} resumption.
load(libdir + "asserts.js");
var g = newGlobal('new-compartment');
var dbg = Debug(g);
dbg.hooks = {
debuggerHandler: function (stack) {
return {throw: "oops"};
}
};
assertThrowsValue(function () { g.eval("debugger;"); }, "oops");
g.eval("function f() { debugger; }");
assertThrowsValue(function () { g.f(); }, "oops");

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Simple {return:} resumption. // Simple {return:} resumption.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
@ -15,5 +13,3 @@ dbg.hooks = {
assertEq(g.eval("debugger; false;"), 1234); assertEq(g.eval("debugger; false;"), 1234);
g.eval("function f() { debugger; return 'bad'; }"); g.eval("function f() { debugger; return 'bad'; }");
assertEq(g.f(), 1234); assertEq(g.f(), 1234);
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// When there are multiple debuggers, their hooks are called in order. // When there are multiple debuggers, their hooks are called in order.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
@ -38,5 +36,3 @@ arr[0].hooks = {
log = ''; log = '';
assertEq(g.eval("debugger; 0;"), 1); assertEq(g.eval("debugger; 0;"), 1);
assertEq(log, 'a'); assertEq(log, 'a');
reportCompare(0, 0, 'ok');

View File

@ -0,0 +1,30 @@
// |jit-test| debug
// Debug.prototype.hooks
load(libdir + 'asserts.js');
var g = newGlobal('new-compartment');
var dbg = new Debug(g);
gc(); // don't assert marking dbg.hooks
var h = dbg.hooks;
assertEq(typeof h, 'object');
assertEq(Object.getOwnPropertyNames(h).length, 0);
assertEq(Object.getPrototypeOf(h), Object.prototype);
assertThrowsInstanceOf(function () { dbg.hooks = null; }, TypeError);
assertThrowsInstanceOf(function () { dbg.hooks = "bad"; }, TypeError);
assertEq(Object.getOwnPropertyNames(dbg).length, 0);
var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "hooks");
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertThrowsInstanceOf(function () { desc.get(); }, TypeError);
assertThrowsInstanceOf(function () { desc.get.call(undefined); }, TypeError);
assertThrowsInstanceOf(function () { desc.get.call(Debug.prototype); }, TypeError);
assertEq(desc.get.call(dbg), h);
assertThrowsInstanceOf(function () { desc.set(); }, TypeError);
assertThrowsInstanceOf(function () { desc.set.call(dbg); }, TypeError);
assertThrowsInstanceOf(function () { desc.set.call({}, {}); }, TypeError);
assertThrowsInstanceOf(function () { desc.set.call(Debug.prototype, {}); }, TypeError);

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// If a hook is deleted after setHooks or overwritten with a primitive, it // If a hook is deleted after setHooks or overwritten with a primitive, it
// simply isn't called. // simply isn't called.
@ -21,5 +19,3 @@ assertEq(hit, false);
dbg.hooks.debuggerHandler = function (stack) { hit = true; }; dbg.hooks.debuggerHandler = function (stack) { hit = true; };
g.eval("debugger;"); g.eval("debugger;");
assertEq(hit, true); assertEq(hit, true);
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Debuggers with enabled hooks should not be GC'd even if they are otherwise // Debuggers with enabled hooks should not be GC'd even if they are otherwise
// unreachable. // unreachable.
@ -20,5 +18,3 @@ f();
gc(); gc(); gc(); gc(); gc(); gc();
g.eval("debugger;"); g.eval("debugger;");
assertEq(actual, expected); assertEq(actual, expected);
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Test adding hooks during dispatch. The behavior is deterministic and "nice", // Test adding hooks during dispatch. The behavior is deterministic and "nice",
// but mainly what we are checking here is that we do not crash due to // but mainly what we are checking here is that we do not crash due to
// modifying a data structure while we're iterating over it. // modifying a data structure while we're iterating over it.
@ -35,5 +33,3 @@ assertEq(hits, 4);
hits = 0; hits = 0;
g.eval("debugger;"); g.eval("debugger;");
assertEq(hits, 8); assertEq(hits, 8);
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Test removing hooks during dispatch. // Test removing hooks during dispatch.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
@ -27,5 +25,3 @@ function addDebug(n) {
addDebug(10); addDebug(10);
g.eval("debugger;"); g.eval("debugger;");
assertEq(log, '0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '); assertEq(log, '0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ');
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Dispatching an event to a debugger must keep enough of it gc-alive to avoid // Dispatching an event to a debugger must keep enough of it gc-alive to avoid
// crashing. // crashing.
@ -35,5 +33,3 @@ addDebug();
hits = 0; hits = 0;
g.eval("debugger;"); g.eval("debugger;");
assertEq(hits, 1); assertEq(hits, 1);
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Q: But who shall debug the debuggers? A: jimb // Q: But who shall debug the debuggers? A: jimb
var log = ''; var log = '';
@ -24,5 +22,3 @@ for (var i = 0; i < 8; i++) // why have 2 debuggers when you can have 8
top = addDebug(top, i); top = addDebug(top, i);
base.eval("debugger;"); base.eval("debugger;");
assertEq(log, '0123456776543210'); assertEq(log, '0123456776543210');
reportCompare(0, 0, 'ok');

View File

@ -1,5 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "enabled"); var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "enabled");
assertEq(typeof desc.get, 'function'); assertEq(typeof desc.get, 'function');
@ -19,5 +18,3 @@ for (var i = 0; i < vals.length; i++) {
g.eval("debugger;"); g.eval("debugger;");
assertEq(hits, vals[i] ? 1 : 0); assertEq(hits, vals[i] ? 1 : 0);
} }
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Disabling a Debug object causes events to stop being delivered to it // Disabling a Debug object causes events to stop being delivered to it
// immediately, even if we're in the middle of dispatching. // immediately, even if we're in the middle of dispatching.
@ -24,5 +22,3 @@ for (var i = 0; i < 4; i++) {
log = ''; log = '';
g.eval("debugger; debugger;"); g.eval("debugger; debugger;");
assertEq(log, '0'); assertEq(log, '0');
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// Uncaught exceptions in the debugger itself are delivered to the // Uncaught exceptions in the debugger itself are delivered to the
// uncaughtExceptionHook. // uncaughtExceptionHook.
@ -22,5 +20,3 @@ dbg.uncaughtExceptionHook = function (exc) {
log = ''; log = '';
g.eval("debugger"); g.eval("debugger");
assertEq(log, 'x!'); assertEq(log, 'x!');
reportCompare(0, 0, 'ok');

View File

@ -1,8 +1,8 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// uncaughtExceptionHook returns a resumption value. // uncaughtExceptionHook returns a resumption value.
load(libdir + "asserts.js");
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var rv; var rv;
@ -19,16 +19,8 @@ g.eval("debugger");
// case 2: throw // case 2: throw
rv = {throw: 57}; rv = {throw: 57};
var result; var result;
try { assertThrowsValue(function () { g.eval("debugger"); }, 57);
g.eval("debugger");
result = 'no exception thrown';
} catch (exc) {
result = 'caught ' + exc;
}
assertEq(result, 'caught 57');
// case 3: return // case 3: return
rv = {return: 42}; rv = {return: 42};
assertEq(g.eval("debugger;"), 42); assertEq(g.eval("debugger;"), 42);
reportCompare(0, 0, 'ok');

View File

@ -1,6 +1,4 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// uncaughtExceptionHook resumption value other than undefined causes further // uncaughtExceptionHook resumption value other than undefined causes further
// hooks to be skipped. // hooks to be skipped.
@ -28,5 +26,3 @@ for (var i = 0; i < 6; i++)
log = ''; log = '';
assertEq(g.eval("debugger;"), 42); assertEq(g.eval("debugger;"), 42);
assertEq(log, "012"); assertEq(log, "012");
reportCompare(0, 0, 'ok');

View File

@ -1,22 +1,20 @@
// Any copyright is dedicated to the Public Domain. // |jit-test| debug
// http://creativecommons.org/licenses/publicdomain/
// dumb basics of uncaughtExceptionHook // dumb basics of uncaughtExceptionHook
load(libdir + 'asserts.js');
var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "uncaughtExceptionHook"); var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "uncaughtExceptionHook");
assertEq(typeof desc.get, 'function'); assertEq(typeof desc.get, 'function');
assertEq(typeof desc.set, 'function'); assertEq(typeof desc.set, 'function');
assertThrows(function () { Debug.prototype.uncaughtExceptionHook = null; }, TypeError); assertThrowsInstanceOf(function () { Debug.prototype.uncaughtExceptionHook = null; }, TypeError);
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
assertEq(desc.get.call(dbg), null); assertEq(desc.get.call(dbg), null);
assertThrows(function () { dbg.uncaughtExceptionHook = []; }, TypeError); assertThrowsInstanceOf(function () { dbg.uncaughtExceptionHook = []; }, TypeError);
assertThrows(function () { dbg.uncaughtExceptionHook = 3; }, TypeError); assertThrowsInstanceOf(function () { dbg.uncaughtExceptionHook = 3; }, TypeError);
dbg.uncaughtExceptionHook = Math.sin; dbg.uncaughtExceptionHook = Math.sin;
assertEq(dbg.uncaughtExceptionHook, Math.sin); assertEq(dbg.uncaughtExceptionHook, Math.sin);
dbg.uncaughtExceptionHook = null; dbg.uncaughtExceptionHook = null;
assertEq(dbg.uncaughtExceptionHook, null); assertEq(dbg.uncaughtExceptionHook, null);
reportCompare(0, 0, 'ok');

View File

@ -103,3 +103,44 @@ BEGIN_TEST(testDebugger_getThisStrict)
return true; return true;
} }
END_TEST(testDebugger_getThisStrict) END_TEST(testDebugger_getThisStrict)
BEGIN_TEST(testDebugger_debugObjectVsDebugMode)
{
CHECK(JS_DefineDebugObject(cx, global));
JSObject *debuggee = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
CHECK(debuggee);
{
JSAutoEnterCompartment ae;
CHECK(ae.enter(cx, debuggee));
CHECK(JS_SetDebugMode(cx, true));
CHECK(JS_InitStandardClasses(cx, debuggee));
}
JSObject *debuggeeWrapper = debuggee;
CHECK(JS_WrapObject(cx, &debuggeeWrapper));
jsval v = OBJECT_TO_JSVAL(debuggeeWrapper);
CHECK(JS_SetProperty(cx, global, "debuggee", &v));
EVAL("var dbg = new Debug(debuggee);\n"
"var hits = 0;\n"
"dbg.hooks = {debuggerHandler: function () { hits++; }};\n"
"debuggee.eval('debugger;');\n"
"hits;\n",
&v);
CHECK_SAME(v, JSVAL_ONE);
{
JSAutoEnterCompartment ae;
CHECK(ae.enter(cx, debuggee));
CHECK(JS_SetDebugMode(cx, false));
}
EVAL("debuggee.eval('debugger; debugger; debugger;');\n"
"hits;\n",
&v);
CHECK_SAME(v, JSVAL_ONE);
return true;
}
END_TEST(testDebugger_debugObjectVsDebugMode)

View File

@ -517,7 +517,10 @@ struct JS_FRIEND_API(JSCompartment) {
const DebugVector &getDebuggers() const { return debuggers; } const DebugVector &getDebuggers() const { return debuggers; }
bool addDebug(js::Debug *dbg) { return debuggers.append(dbg); } bool addDebug(js::Debug *dbg) {
JS_ASSERT(debugMode);
return debuggers.append(dbg);
}
void removeDebug(js::Debug *dbg); void removeDebug(js::Debug *dbg);
}; };

View File

@ -306,10 +306,16 @@ void
Debug::finalize(JSContext *cx, JSObject *obj) Debug::finalize(JSContext *cx, JSObject *obj)
{ {
Debug *dbg = (Debug *) obj->getPrivate(); Debug *dbg = (Debug *) obj->getPrivate();
if (dbg && dbg->debuggeeCompartment) { if (dbg && dbg->debuggeeCompartment)
dbg->debuggeeCompartment->removeDebug(dbg); dbg->detachFrom(dbg->debuggeeCompartment);
dbg->debuggeeCompartment = NULL; }
}
void
Debug::detachFrom(JSCompartment *c)
{
JS_ASSERT(c == debuggeeCompartment);
c->removeDebug(this);
debuggeeCompartment = NULL;
} }
Class Debug::jsclass = { Class Debug::jsclass = {
@ -411,6 +417,13 @@ Debug::construct(JSContext *cx, uintN argc, Value *vp)
return false; return false;
} }
// Check that the target compartment is in debug mode.
JSCompartment *debuggeeCompartment = argobj->getProxyPrivate().toObject().compartment();
if (!debuggeeCompartment->debugMode) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DEBUG_MODE);
return false;
}
// Get Debug.prototype. // Get Debug.prototype.
Value v; Value v;
jsid prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); jsid prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
@ -426,7 +439,6 @@ Debug::construct(JSContext *cx, uintN argc, Value *vp)
JSObject *hooks = NewBuiltinClassInstance(cx, &js_ObjectClass); JSObject *hooks = NewBuiltinClassInstance(cx, &js_ObjectClass);
if (!hooks) if (!hooks)
return false; return false;
JSCompartment *debuggeeCompartment = argobj->getProxyPrivate().toObject().compartment();
Debug *dbg = cx->new_<Debug>(obj, hooks, debuggeeCompartment); Debug *dbg = cx->new_<Debug>(obj, hooks, debuggeeCompartment);
if (!dbg) if (!dbg)
return false; return false;

View File

@ -110,6 +110,7 @@ class Debug {
static inline Debug *fromJSObject(JSObject *obj); static inline Debug *fromJSObject(JSObject *obj);
inline bool observesCompartment(JSCompartment *c) const; inline bool observesCompartment(JSCompartment *c) const;
void detachFrom(JSCompartment *c);
static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp); static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp);
}; };

View File

@ -51,6 +51,7 @@
#include "jsapi.h" #include "jsapi.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jsversion.h" #include "jsversion.h"
#include "jsdbg.h"
#include "jsdbgapi.h" #include "jsdbgapi.h"
#include "jsemit.h" #include "jsemit.h"
#include "jsfun.h" #include "jsfun.h"
@ -193,9 +194,16 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
// All scripts compiled from this point on should be in the requested debugMode. // All scripts compiled from this point on should be in the requested debugMode.
comp->debugMode = !!debug; comp->debugMode = !!debug;
// Detach any debuggers attached to this compartment.
if (debug) {
JS_ASSERT(comp->getDebuggers().empty());
} else {
while (!comp->getDebuggers().empty())
comp->getDebuggers().back()->detachFrom(comp);
}
// Discard JIT code for any scripts that change debugMode. This function // Discard JIT code for any scripts that change debugMode. This function
// assumes that 'comp' is in the same thread as 'cx'. // assumes that 'comp' is in the same thread as 'cx'.
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
JS::AutoEnterScriptCompartment ac; JS::AutoEnterScriptCompartment ac;

View File

@ -1,10 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
checkFunction(this, "Debug", 1);
assertEq(Debug.prototype.constructor, Debug);
assertEq(Object.prototype.toString.call(Debug.prototype), "[object Debug]");
assertEq(Object.getPrototypeOf(Debug.prototype), Object.prototype);
reportCompare(0, 0, 'ok');

View File

@ -1,37 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Debug rejects arguments that aren't cross-compartment wrappers.
assertThrows(function () { Debug(); }, TypeError);
assertThrows(function () { Debug(null); }, TypeError);
assertThrows(function () { Debug(true); }, TypeError);
assertThrows(function () { Debug(42); }, TypeError);
assertThrows(function () { Debug("bad"); }, TypeError);
assertThrows(function () { Debug(function () {}); }, TypeError);
assertThrows(function () { Debug(this); }, TypeError);
assertThrows(function () { new Debug(); }, TypeError);
assertThrows(function () { new Debug(null); }, TypeError);
assertThrows(function () { new Debug(true); }, TypeError);
assertThrows(function () { new Debug(42); }, TypeError);
assertThrows(function () { new Debug("bad"); }, TypeError);
assertThrows(function () { new Debug(function () {}); }, TypeError);
assertThrows(function () { new Debug(this); }, TypeError);
// Very basic tests of Debug creation.
var g = newGlobal('new-compartment');
var dbg = new Debug(g);
assertEq(dbg instanceof Debug, true);
assertEq(Object.getPrototypeOf(dbg), Debug.prototype);
// The reverse.
var g2 = newGlobal('new-compartment');
g2.debuggeeGlobal = this;
g2.eval("var dbg = new Debug(debuggeeGlobal);");
assertEq(g2.eval("dbg instanceof Debug"), true);
// The Debug constructor from this compartment will not accept as its argument
// an Object from this compartment. Shenanigans won't fool the membrane.
g2.outer = this;
assertThrows(function () { g2.eval("outer.Debug(outer.Object())"); }, TypeError);
reportCompare(0, 0, 'ok');

View File

@ -1,32 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Simple {throw:} resumption.
var g = newGlobal('new-compartment');
var dbg = Debug(g);
dbg.hooks = {
debuggerHandler: function (stack) {
return {throw: "oops"};
}
};
var result = 'no exception thrown';
try {
g.eval("debugger;");
} catch (exc) {
result = exc;
}
assertEq(result, "oops");
g.eval("function f() { debugger; }");
result = 'no exception thrown';
try {
g.f();
} catch (exc) {
result = exc;
}
assertEq(result, "oops");
reportCompare(0, 0, 'ok');

View File

@ -1,32 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Debug.prototype.hooks
var g = newGlobal('new-compartment');
var dbg = new Debug(g);
gc(); // don't assert marking dbg.hooks
var h = dbg.hooks;
assertEq(typeof h, 'object');
assertEq(Object.getOwnPropertyNames(h).length, 0);
assertEq(Object.getPrototypeOf(h), Object.prototype);
assertThrows(function () { dbg.hooks = null; }, TypeError);
assertThrows(function () { dbg.hooks = "bad"; }, TypeError);
assertEq(Object.getOwnPropertyNames(dbg).length, 0);
var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "hooks");
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertThrows(function () { desc.get(); }, TypeError);
assertThrows(function () { desc.get.call(undefined); }, TypeError);
assertThrows(function () { desc.get.call(Debug.prototype); }, TypeError);
assertEq(desc.get.call(dbg), h);
assertThrows(function () { desc.set(); }, TypeError);
assertThrows(function () { desc.set.call(dbg); }, TypeError);
assertThrows(function () { desc.set.call({}, {}); }, TypeError);
assertThrows(function () { desc.set.call(Debug.prototype, {}); }, TypeError);
reportCompare(0, 0, 'ok');

View File

@ -42,24 +42,3 @@ script regress-636697.js
script is-generator.js script is-generator.js
script weakmap.js script weakmap.js
script regress-650753.js script regress-650753.js
skip-if(!xulRuntime.shell) script debug-object-01.js
skip-if(!xulRuntime.shell) script debug-object-02.js
skip-if(!xulRuntime.shell) script debug-object-03.js
skip-if(!xulRuntime.shell) script debug-object-04.js
skip-if(!xulRuntime.shell) script debug-object-05.js
skip-if(!xulRuntime.shell) script debug-object-06.js
skip-if(!xulRuntime.shell) script debug-object-07.js
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
skip-if(!xulRuntime.shell) script debug-object-18.js
skip-if(!xulRuntime.shell) script debug-object-19.js
skip-if(!xulRuntime.shell) script debug-object-20.js
skip-if(!xulRuntime.shell) script debug-object-21.js

View File

@ -170,14 +170,3 @@ var Match =
MatchError: MatchError }; MatchError: MatchError };
})(); })();
// used by several Debug object tests
function checkFunction(obj, name, nargs) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
assertEq(desc.configurable, true, name + " should be configurable");
assertEq(desc.writable, true, name + " should be writable");
assertEq(desc.enumerable, false, name + " should be non-enumerable");
assertEq(desc.value, obj[name]); // well obviously
assertEq(typeof desc.value, 'function', name + " should be a function");
assertEq(desc.value.length, nargs, name + " should have .length === " + nargs);
}