Automatically turn debug mode on/off when adding/removing debuggees.

This allows most of the tests to run without the -d command-line flag.

Now a compartment is in debug mode if
 * JSD1 wants debug mode on, thanks to a JS_SetDebugMode* call; OR
 * JSD2 wants debug mode on, because a live Debug object has a debuggee
   global in that compartment.

Since this patch only adds the second half of the rule, JSD1 should be
unaffected.

The new rule has three issues:

1. When removeDebuggee is called, it can cause debug mode to be turned
   off for a compartment. If any scripts from that compartment are on
   the stack, and the methodjit is enabled, returning to those stack
   frames will crash.

2. When a Debug object is GC'd, it can cause debug mode to be turned off
   for one or more compartments. This causes the same problem with
   returning to deleted methodjit code, but the fix is different: such
   Debug objects simply should not be GC'd.

3. Setting .enabled to false still does not turn off debug mode
   anywhere, so it does not reduce overhead as much as it should.

A possible fix for issue #1 would be to make such removeDebuggee calls
throw.  The fix to issues #2 and #3 is to tweak the rule--and to tweak
the rule for Debug object GC-reachability.

--HG--
rename : js/src/jit-test/tests/debug/Debug-ctor.js => js/src/jit-test/tests/debug/Debug-ctor-01.js
This commit is contained in:
Jason Orendorff 2011-06-02 21:58:46 -05:00
parent 2ed818c0ac
commit 6a958619a0
113 changed files with 310 additions and 408 deletions

View File

@ -1,5 +1,3 @@
// |jit-test| debug
load(libdir + 'asserts.js'); load(libdir + 'asserts.js');
// Debug rejects arguments that aren't cross-compartment wrappers. // Debug rejects arguments that aren't cross-compartment wrappers.
@ -21,14 +19,3 @@ var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
assertEq(dbg instanceof Debug, true); assertEq(dbg instanceof Debug, true);
assertEq(Object.getPrototypeOf(dbg), Debug.prototype); 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

@ -0,0 +1,17 @@
// |jit-test| debug
// Test creating a Debug in a sandbox, debugging the initial global.
//
// This requires debug mode to already be on in the initial global, since it's
// always on the stack in the shell. Hence the |jit-test| tag.
load(libdir + 'asserts.js');
var g = newGlobal('new-compartment');
g.debuggeeGlobal = this;
g.eval("var dbg = new Debug(debuggeeGlobal);");
assertEq(g.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.
g.parent = this;
assertThrowsInstanceOf(function () { g.eval("parent.Debug(parent.Object())"); }, TypeError);

View File

@ -0,0 +1,6 @@
// If the debuggee cannot be put into debug mode, throw.
var g = newGlobal('new-compartment');
g.libdir = libdir;
g.eval("load(libdir + 'asserts.js');");
g.parent = this;
g.eval("assertThrowsInstanceOf(function () { new Debug(parent); }, Error);");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// A Debug object created with no argument initially has no debuggees. // A Debug object created with no argument initially has no debuggees.
var dbg = new Debug; var dbg = new Debug;
var debuggees = dbg.getDebuggees(); var debuggees = dbg.getDebuggees();

View File

@ -1,5 +1,4 @@
// |jit-test| debug // The array returned by getDebuggees is just a snapshot, not live.
// The array returned by getDebuggees is just a snapshot, not live
var dbg = new Debug; var dbg = new Debug;
var a1 = dbg.getDebuggees(); var a1 = dbg.getDebuggees();
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Debug hooks fire based on debuggees. // Debug hooks fire based on debuggees.
var g1 = newGlobal('new-compartment'); var g1 = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// hasDebuggee tests. // hasDebuggee tests.
var g1 = newGlobal('new-compartment'), g1w; var g1 = newGlobal('new-compartment'), g1w;

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// addDebuggee returns different Debug.Object wrappers for different Debug objects. // addDebuggee returns different Debug.Object wrappers for different Debug objects.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// {has,add,remove}Debuggee throw a TypeError if the argument is invalid. // {has,add,remove}Debuggee throw a TypeError if the argument is invalid.
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Handle proto-less objects passed to addDebuggee. // Handle proto-less objects passed to addDebuggee.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// addDebuggee(obj), where obj is not global, adds obj's global. // addDebuggee(obj), where obj is not global, adds obj's global.
// Adding a debuggee more than once is redundant. // Adding a debuggee more than once is redundant.

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Allow diamonds in the graph of the compartment "debugs" relation. // Allow diamonds in the graph of the compartment "debugs" relation.
var program = newGlobal('new-compartment'); var program = newGlobal('new-compartment');
var d1 = newGlobal('new-compartment'); var d1 = newGlobal('new-compartment');
d1.top = this; d1.top = this;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Events in a non-debuggee are ignored, even if a debuggee is in the same compartment. // Events in a non-debuggee are ignored, even if a debuggee is in the same compartment.
var g1 = newGlobal('new-compartment'); var g1 = newGlobal('new-compartment');
var g2 = g1.eval("newGlobal('same-compartment')"); var g2 = g1.eval("newGlobal('same-compartment')");
var dbg = new Debug(g1); var dbg = new Debug(g1);

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Removing a debuggee does not detach the debugger from a compartment if another debuggee is in it. // Removing a debuggee does not detach the debugger from a compartment if another debuggee is in it.
var g1 = newGlobal('new-compartment'); var g1 = newGlobal('new-compartment');
var g2 = g1.eval("newGlobal('same-compartment')"); var g2 = g1.eval("newGlobal('same-compartment')");
var dbg = new Debug(g1, g2); var dbg = new Debug(g1, g2);

View File

@ -1,11 +1,7 @@
// Reject non-debug-mode debuggees without asserting. // Adding a debuggee in a compartment that is already in debug mode works
// even if a script from that compartment is on the stack.
load(libdir + "asserts.js");
function f() {
var v = new Debug;
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
v.addDebuggee(g); // don't assert var dbg1 = Debug(g);
} var dbg2 = Debug();
g.parent = this;
assertThrowsInstanceOf(f, Error); g.eval("parent.dbg2.addDebuggee(this);");

View File

@ -1,5 +1,3 @@
// |jit-test| debug
var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "enabled"); var desc = Object.getOwnPropertyDescriptor(Debug.prototype, "enabled");
assertEq(typeof desc.get, 'function'); assertEq(typeof desc.get, 'function');
assertEq(typeof desc.set, 'function'); assertEq(typeof desc.set, 'function');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// getYoungestFrame basics. // getYoungestFrame basics.
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Hooks and Debug.prototype.getYoungestFrame produce the same Frame object. // Hooks and Debug.prototype.getYoungestFrame produce the same Frame object.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Q: But who shall debug the debuggers? A: jimb // Q: But who shall debug the debuggers? A: jimb
var log = ''; var log = '';

View File

@ -1,14 +1,10 @@
// |jit-test| debug
// Test .type and .generator fields of topmost stack frame passed to debuggerHandler. // Test .type and .generator fields of topmost stack frame passed to debuggerHandler.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.debuggeeGlobal = this; var dbg = Debug(g);
g.eval("var hits;"); var expected, hits;
g.eval("(" + function () {
var dbg = Debug(debuggeeGlobal);
dbg.hooks = { dbg.hooks = {
debuggerHandler: function (f) { debuggerHandler: function (f) {
// print(uneval(expected));
assertEq(Object.getPrototypeOf(f), Debug.Frame.prototype); assertEq(Object.getPrototypeOf(f), Debug.Frame.prototype);
assertEq(f.type, expected.type); assertEq(f.type, expected.type);
assertEq(f.generator, expected.generator); assertEq(f.generator, expected.generator);
@ -16,55 +12,22 @@ g.eval("(" + function () {
hits++; hits++;
} }
}; };
} + ")()");
g.expected = { type:"global", generator:false, constructing:false }; function test(code, expectobj, expectedHits) {
g.hits = 0; expected = expectobj;
debugger; hits = 0;
assertEq(g.hits, 1); g.evaluate(code);
assertEq(hits, arguments.length < 3 ? 1 : expectedHits);
g.expected = { type:"call", generator:false, constructing:false };
g.hits = 0;
(function () { debugger; })();
assertEq(g.hits, 1);
g.expected = { type:"call", generator:false, constructing:true };
g.hits = 0;
new function() { debugger; };
assertEq(g.hits, 1);
g.expected = { type:"call", generator:false, constructing:false };
g.hits = 0;
new function () {
(function() { debugger; })();
assertEq(g.hits, 1);
} }
g.expected = { type:"eval", generator:false, constructing:false }; test("debugger;", {type: "global", generator: false, constructing: false});
g.hits = 0; test("(function () { debugger; })();", {type: "call", generator: false, constructing: false});
eval("debugger;"); test("new function() { debugger; };", {type: "call", generator: false, constructing: true});
assertEq(g.hits, 1); test("new function () { (function() { debugger; })(); }", {type: "call", generator: false, constructing: false});
test("eval('debugger;');", {type: "eval", generator: false, constructing: false});
g.expected = { type:"eval", generator:false, constructing:false }; test("this.eval('debugger;'); // indirect eval", {type: "eval", generator: false, constructing: false});
g.hits = 0; test("(function () { eval('debugger;'); })();", {type: "eval", generator: false, constructing: false});
this.eval("debugger;"); // indirect eval test("new function () { eval('debugger'); }", {type: "eval", generator: false, constructing: false});
assertEq(g.hits, 1); test("function gen() { debugger; yield 1; debugger; }\n" +
"for (var x in gen()) {}\n",
g.expected = { type:"eval", generator:false, constructing:false }; {type: "call", generator: true, constructing: false}, 2);
g.hits = 0;
(function () { eval("debugger;"); })();
assertEq(g.hits, 1);
g.expected = { type:"eval", generator:false, constructing:false };
g.hits = 0;
new function () {
eval("debugger");
assertEq(g.hits, 1);
}
g.expected = { type:"call", generator:true, constructing:false };
g.hits = 0;
function gen() { debugger; yield 1; debugger; }
for (var x in gen()) {
}
assertEq(g.hits, 2);

View File

@ -1,12 +1,9 @@
// |jit-test| debug
// When the debugger is triggered twice from the same stack frame, the same // When the debugger is triggered twice from the same stack frame, the same
// Debug.Frame object must be passed to the hook both times. // Debug.Frame object must be passed to the hook both times.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.debuggeeGlobal = this; var hits, frame;
g.eval("var hits, frame;"); var dbg = Debug(g);
g.eval("(" + function () {
var dbg = Debug(debuggeeGlobal);
dbg.hooks = { dbg.hooks = {
debuggerHandler: function (f) { debuggerHandler: function (f) {
if (hits++ == 0) if (hits++ == 0)
@ -15,21 +12,15 @@ g.eval("(" + function () {
assertEq(f, frame); assertEq(f, frame);
} }
}; };
} + ")()");
g.hits = 0; hits = 0;
debugger; g.evaluate("debugger; debugger;");
debugger; assertEq(hits, 2);
assertEq(g.hits, 2);
g.hits = 0; hits = 0;
function f() { g.evaluate("function f() { debugger; debugger; } f();");
debugger; assertEq(hits, 2);
debugger;
}
f();
assertEq(g.hits, 2);
g.hits = 0; hits = 0;
eval("debugger; debugger;"); g.evaluate("eval('debugger; debugger;');");
assertEq(g.hits, 2); assertEq(hits, 2);

View File

@ -1,13 +1,10 @@
// |jit-test| debug
// When the debugger is triggered from different stack frames that happen to // When the debugger is triggered from different stack frames that happen to
// occupy the same memory, it must deliver different Debug.Frame objects. // occupy the same memory, it must deliver different Debug.Frame objects.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.debuggeeGlobal = this; var dbg = Debug(g);
g.eval("var hits;"); var hits;
g.eval("(" + function () {
var a = []; var a = [];
var dbg = Debug(debuggeeGlobal);
dbg.hooks = { dbg.hooks = {
debuggerHandler: function (frame) { debuggerHandler: function (frame) {
for (var i = 0; i < a.length; i++) for (var i = 0; i < a.length; i++)
@ -16,11 +13,9 @@ g.eval("(" + function () {
hits++; hits++;
} }
}; };
} + ")()");
function f() { debugger; } g.eval("function f() { debugger; }");
function h() { debugger; f(); } g.eval("function h() { debugger; f(); }");
g.hits = 0; hits = 0;
for (var i = 0; i < 4; i++) g.eval("for (var i = 0; i < 4; i++) h();");
h(); assertEq(hits, 8);
assertEq(g.hits, 8);

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Frame.prototype.arguments with primitive values // Frame.prototype.arguments with primitive values
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Object arguments. // Object arguments.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Destructuring arguments. // Destructuring arguments.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// frame.arguments works for all live frames // frame.arguments works for all live frames
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// frame.arguments is "live" (it reflects assignments to arguments). // frame.arguments is "live" (it reflects assignments to arguments).
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Test extracting frame.arguments element getters and calling them in // Test extracting frame.arguments element getters and calling them in
// various awkward ways. // various awkward ways.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// simplest possible test of Debug.Frame.prototype.eval // simplest possible test of Debug.Frame.prototype.eval
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// frame.eval() throws if frame is not live // frame.eval() throws if frame is not live
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Test eval-ing names in a topmost script frame // Test eval-ing names in a topmost script frame
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// frame.eval SyntaxErrors are reflected, not thrown // frame.eval SyntaxErrors are reflected, not thrown
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// var declarations in strict frame.eval do not modify the frame // var declarations in strict frame.eval do not modify the frame
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// frame.eval throws if frame is a generator frame that isn't currently on the stack // frame.eval throws if frame is a generator frame that isn't currently on the stack
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// test frame.eval in non-top frames // test frame.eval in non-top frames
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// The arguments can escape from a function via a debugging hook. // The arguments can escape from a function via a debugging hook.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// assigning to local variables in frame.eval code // assigning to local variables in frame.eval code
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// frame.eval returns null if the eval code fails with an uncatchable error. // frame.eval returns null if the eval code fails with an uncatchable error.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// evalWithBindings basics // evalWithBindings basics
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// evalWithBindings to call a method of a debuggee object // evalWithBindings to call a method of a debuggee object
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug; var dbg = new Debug;
var global = dbg.addDebuggee(g); var global = dbg.addDebuggee(g);

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// arguments works in evalWithBindings (it does not interpose a function scope) // arguments works in evalWithBindings (it does not interpose a function scope)
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug; var dbg = new Debug;
var global = dbg.addDebuggee(g); var global = dbg.addDebuggee(g);

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// evalWithBindings works on non-top frames. // evalWithBindings works on non-top frames.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var f1; var f1;

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// evalWithBindings code can assign to the bindings. // evalWithBindings code can assign to the bindings.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// In evalWithBindings code, assignment to any name not in the bindings works just as in eval. // In evalWithBindings code, assignment to any name not in the bindings works just as in eval.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
dbg.hooks = { dbg.hooks = {

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// var statements in strict evalWithBindings code behave like strict eval. // var statements in strict evalWithBindings code behave like strict eval.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var hits = 0; var hits = 0;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// evalWithBindings ignores non-enumerable and non-own properties. // evalWithBindings ignores non-enumerable and non-own properties.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var hits = 0; var hits = 0;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// evalWithBindings code is debuggee code, so it can trip the debugger. It nests! // evalWithBindings code is debuggee code, so it can trip the debugger. It nests!
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var f1; var f1;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Direct eval code under evalWithbindings sees both the bindings and the enclosing scope. // Direct eval code under evalWithbindings sees both the bindings and the enclosing scope.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var hits = 0; var hits = 0;

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Test that on-stack Debug.Frames are not GC'd even if they are only reachable // Test that on-stack Debug.Frames are not GC'd even if they are only reachable
// from the js::Debug::frames table. // from the js::Debug::frames table.

View File

@ -4,18 +4,15 @@
load(libdir + "asserts.js"); load(libdir + "asserts.js");
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.debuggeeGlobal = this; var f;
g.eval("var f;"); Debug(g).hooks = {
g.eval("(" + function () {
Debug(debuggeeGlobal).hooks = {
debuggerHandler: function (frame) { debuggerHandler: function (frame) {
assertEq(frame.type, "call"); assertEq(frame.type, "call");
assertEq(frame.live, true); assertEq(frame.live, true);
f = frame; f = frame;
} }
}; };
} + ")()");
(function () { debugger; })(); g.eval("(function () { debugger; })();");
assertEq(g.f.live, false); assertEq(f.live, false);
assertThrowsInstanceOf(function () { g.f.type; }, g.Error); assertThrowsInstanceOf(function () { f.type; }, Error);

View File

@ -0,0 +1,28 @@
// Frame.live is false for frames discarded during uncatchable error unwinding.
var g = newGlobal('new-compartment');
var dbg = Debug(g);
var hits = 0;
var snapshot;
dbg.hooks = {
debuggerHandler: function (frame) {
var stack = [];
for (var f = frame; f; f = f.older) {
if (f.type === "call")
stack.push(f);
}
snapshot = stack;
if (hits++ === 0)
assertEq(frame.eval("x();"), null);
else
return null;
}
};
g.eval("function z() { debugger; }");
g.eval("function y() { z(); }");
g.eval("function x() { y(); }");
assertEq(g.eval("debugger; 'ok';"), "ok");
assertEq(hits, 2);
assertEq(snapshot.length, 3);
for (var i = 0; i < snapshot.length; i++)
assertEq(snapshot[i].live, false);

View File

@ -2,10 +2,8 @@
// Basic call chain. // Basic call chain.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.debuggeeGlobal = this; var result = null;
g.result = null; var dbg = new Debug(g);
g.eval("(" + function () {
var dbg = new Debug(debuggeeGlobal);
dbg.hooks = { dbg.hooks = {
debuggerHandler: function (frame) { debuggerHandler: function (frame) {
var a = []; var a = [];
@ -16,10 +14,9 @@ g.eval("(" + function () {
result = a.join(", "); result = a.join(", ");
} }
}; };
} + ")();");
function first() { return second(); } g.eval("function first() { return second(); }");
function second() { return eval("third()"); } g.eval("function second() { return eval('third()'); }");
function third() { debugger; } g.eval("function third() { debugger; }");
first(); g.evaluate("first();");
assertEq(g.result, "global, first, second, eval, third"); assertEq(result, "global, first, second, eval, third");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Frame.prototype.this in strict-mode functions, with primitive values // Frame.prototype.this in strict-mode functions, with primitive values
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Frame.prototype.this in strict direct eval frames // Frame.prototype.this in strict direct eval frames
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Frame.prototype.this in non-strict-mode functions, with primitive values // Frame.prototype.this in non-strict-mode functions, with primitive values
function classOf(obj) { function classOf(obj) {

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Debug.Frame.prototype.this in functions, with object values // Debug.Frame.prototype.this in functions, with object values
function classOf(obj) { function classOf(obj) {

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Debug.Object basics // Debug.Object basics
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// tests calling script functions via Debug.Object.prototype.apply/call // tests calling script functions via Debug.Object.prototype.apply/call
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// tests calling native functions via Debug.Object.prototype.apply/call // tests calling native functions via Debug.Object.prototype.apply/call
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// reentering the debugger several times via debuggerHandler and apply/call on a single stack // reentering the debugger several times via debuggerHandler and apply/call on a single stack
var g = newGlobal("new-compartment"); var g = newGlobal("new-compartment");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Debug.Object.prototype.apply/call works with function proxies // Debug.Object.prototype.apply/call works with function proxies
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Test Debug.Object.prototype.callable. // Test Debug.Object.prototype.callable.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,5 +1,4 @@
// |jit-test| debug // Basic tests for Debug.Object.prototype.class.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = new Debug(g); var dbg = new Debug(g);
var hits = 0; var hits = 0;
@ -14,6 +13,5 @@ dbg.hooks = {
hits++; hits++;
} }
}; };
g.eval("(function () { debugger; })(Object.prototype, [], eval, new Date, Proxy.create({}));"); g.eval("(function () { debugger; })(Object.prototype, [], eval, new Date, Proxy.create({}));");
assertEq(hits, 1); assertEq(hits, 1);

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Two references to the same object get the same Debug.Object wrapper. // Two references to the same object get the same Debug.Object wrapper.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);
var hits = 0; var hits = 0;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Different objects get different Debug.Object wrappers. // Different objects get different Debug.Object wrappers.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);
var hits = 0; var hits = 0;

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// The same object gets the same Debug.Object wrapper at different times, if the difference would be observable. // The same object gets the same Debug.Object wrapper at different times, if the difference would be observable.
var N = HOTLOOP + 4; var N = HOTLOOP + 4;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Debug.Object.prototype.name // Debug.Object.prototype.name
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);
var name, hits; var name, hits;

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// The .name of a non-function object is undefined. // The .name of a non-function object is undefined.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var hits = 0; var hits = 0;
var dbg = new Debug(g); var dbg = new Debug(g);

View File

@ -1,4 +1,3 @@
// |jit-test| debug
load(libdir + 'array-compare.js'); load(libdir + 'array-compare.js');
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,4 @@
// |jit-test| debug // Debug.Object.prototype.proto
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbgeval = function () { var dbgeval = function () {
var dbg = new Debug(g); var dbg = new Debug(g);

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Test removing hooks during dispatch. // Test removing hooks during dispatch.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Storing a property on a Debug.Object protects it from GC as long as the // Storing a property on a Debug.Object protects it from GC as long as the
// referent is alive. // referent is alive.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Storing a Debug.Object as a key in a WeakMap protects it from GC as long as // Storing a Debug.Object as a key in a WeakMap protects it from GC as long as
// the referent is alive. // the referent is alive.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// If a Debug survives its debuggee, its object cache must still be swept. // If a Debug survives its debuggee, its object cache must still be swept.
var g2arr = []; // non-debuggee globals var g2arr = []; // non-debuggee globals

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Debug objects do not keep debuggee globals live. // Debug objects do not keep debuggee globals live.
var dbg = new Debug; var dbg = new Debug;
for (var i = 0; i < 4; i++) for (var i = 0; i < 4; i++)
dbg.addDebuggee(newGlobal('new-compartment')); dbg.addDebuggee(newGlobal('new-compartment'));

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// Don't assert with dead Debug.Object and live cross-compartment wrapper of referent. // Don't assert with dead Debug.Object and live cross-compartment wrapper of referent.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
for (var j = 0; j < 4; j++) { for (var j = 0; j < 4; j++) {
var dbg = new Debug; var dbg = new Debug;

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Debuggers with enabled throw hooks should not be GC'd even if they are // Debuggers with enabled throw hooks should not be GC'd even if they are
// otherwise unreachable. // otherwise unreachable.

View File

@ -1,13 +1,8 @@
// |jit-test| debug
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
g.log = ''; g.log = '';
var dbg = Debug(g); var dbg = Debug(g);
var hooks = { var hooks = {debuggerHandler: function (stack) { g.log += '!'; }};
debuggerHandler: function (stack) {
g.log += '!';
}
};
dbg.hooks = hooks; 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);

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// 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.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Basic throw hook test. // Basic throw hook test.
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,6 +1,4 @@
// |jit-test| debug
// hooks.throw is not called for exceptions thrown and handled in the debugger. // hooks.throw is not called for exceptions thrown and handled in the debugger.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);
g.log = ''; g.log = '';

View File

@ -1,10 +1,8 @@
// |jit-test| debug
// Simple {throw:} resumption. // Simple {throw:} resumption.
load(libdir + "asserts.js"); load(libdir + "asserts.js");
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);
dbg.hooks = { dbg.hooks = {
debuggerHandler: function (stack) { debuggerHandler: function (stack) {

View File

@ -1,8 +1,5 @@
// |jit-test| debug
// Simple {return:} resumption. // Simple {return:} resumption.
var g = newGlobal('new-compartment'); var g = newGlobal('new-compartment');
var dbg = Debug(g); var dbg = Debug(g);
dbg.hooks = { dbg.hooks = {
debuggerHandler: function (stack) { debuggerHandler: function (stack) {

View File

@ -1,4 +1,4 @@
// |jit-test| debug // Check superficial characteristics of functions and properties (not functionality).
function checkFunction(obj, name, nargs) { function checkFunction(obj, name, nargs) {
var desc = Object.getOwnPropertyDescriptor(obj, name); var desc = Object.getOwnPropertyDescriptor(obj, name);

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Debug.prototype.hooks // Debug.prototype.hooks
load(libdir + 'asserts.js'); load(libdir + 'asserts.js');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// dumb basics of uncaughtExceptionHook // dumb basics of uncaughtExceptionHook
load(libdir + 'asserts.js'); load(libdir + 'asserts.js');

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Uncaught exceptions in the debugger itself are delivered to the // Uncaught exceptions in the debugger itself are delivered to the
// uncaughtExceptionHook. // uncaughtExceptionHook.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// Returning a bad resumption value causes an exception that is reported to the // Returning a bad resumption value causes an exception that is reported to the
// uncaughtExceptionHook. // uncaughtExceptionHook.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// uncaughtExceptionHook returns a resumption value. // uncaughtExceptionHook returns a resumption value.
load(libdir + "asserts.js"); load(libdir + "asserts.js");

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// uncaughtExceptionHook resumption value other than undefined causes further // uncaughtExceptionHook resumption value other than undefined causes further
// hooks to be skipped. // hooks to be skipped.

View File

@ -1,4 +1,3 @@
// |jit-test| debug
// After hooks.throw throws, if uncaughtExceptionHook returns undefined, // After hooks.throw throws, if uncaughtExceptionHook returns undefined,
// the original exception continues to propagate. // the original exception continues to propagate.

View File

@ -315,7 +315,7 @@ Script::analyze(JSContext *cx, JSScript *script)
* by debug code or by eval, or if they could be accessed by an inner script. * by debug code or by eval, or if they could be accessed by an inner script.
*/ */
if (script->usesEval || cx->compartment->debugMode) { if (script->usesEval || cx->compartment->debugMode()) {
for (uint32 i = 0; i < nfixed; i++) for (uint32 i = 0; i < nfixed; i++)
setLocal(i, LOCAL_USE_BEFORE_DEF); setLocal(i, LOCAL_USE_BEFORE_DEF);
} }
@ -330,7 +330,7 @@ Script::analyze(JSContext *cx, JSScript *script)
* If the script is in debug mode, JS_SetFrameReturnValue can be called at * If the script is in debug mode, JS_SetFrameReturnValue can be called at
* any safe point. * any safe point.
*/ */
if (cx->compartment->debugMode) if (cx->compartment->debugMode())
usesRval = true; usesRval = true;
/* /*

View File

@ -139,7 +139,7 @@ BEGIN_TEST(testDebugger_debugObjectVsDebugMode)
EVAL("debuggee.eval('debugger; debugger; debugger;');\n" EVAL("debuggee.eval('debugger; debugger; debugger;');\n"
"hits;\n", "hits;\n",
&v); &v);
CHECK_SAME(v, JSVAL_ONE); CHECK_SAME(v, INT_TO_JSVAL(4));
return true; return true;
} }

Some files were not shown because too many files have changed in this diff Show More