Backed out changeset 2c5e99c6de6a (bug 1564168) for causing bustages in Debugger-enabled-01.binjs CLOSED TREE

This commit is contained in:
Noemi Erli 2019-07-26 01:27:37 +03:00
parent 32ebfab7db
commit 8f73896852
35 changed files with 355 additions and 46 deletions

View File

@ -34,5 +34,5 @@ function run_test()
g.stopMe(doc.createEvent("MouseEvent"));
} + ")()");
dbg.removeAllDebuggees();
dbg.enabled = false;
}

View File

@ -316,7 +316,9 @@ Breakpoint::Breakpoint(Debugger* debugger, BreakpointSite* site,
void Breakpoint::destroy(FreeOp* fop,
MayDestroySite mayDestroySite /* true */) {
site->dec(fop);
if (debugger->enabled) {
site->dec(fop);
}
debugger->breakpoints.remove(this);
site->breakpoints.remove(this);
gc::Cell* cell = site->owningCellUnbarriered();
@ -371,6 +373,7 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg)
: object(dbg),
debuggees(cx->zone()),
uncaughtExceptionHook(nullptr),
enabled(true),
allowUnobservedAsmJS(false),
collectCoverageInfo(false),
observedGCs(cx->zone()),
@ -623,8 +626,8 @@ static bool DebuggerExists(GlobalObject* global,
/* static */
bool Debugger::hasLiveHook(GlobalObject* global, Hook which) {
return DebuggerExists(global, [=](Debugger* dbg) {
return dbg->getHook(which);
});
return dbg->enabled && dbg->getHook(which);
});
}
/* static */
@ -665,6 +668,10 @@ JSObject* Debugger::getHook(Hook hook) const {
}
bool Debugger::hasAnyLiveHooks(JSRuntime* rt) const {
if (!enabled) {
return false;
}
// A onNewGlobalObject hook does not hold its Debugger live, so its behavior
// is nondeterministic. This behavior is not satisfying, but it is at least
// documented.
@ -903,7 +910,7 @@ bool DebugAPI::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame,
Debugger* dbg = Debugger::fromChildJSObject(frameobj);
EnterDebuggeeNoExecute nx(cx, *dbg, adjqi);
if (frameobj->isLive() && frameobj->onPopHandler()) {
if (dbg->enabled && frameobj->isLive() && frameobj->onPopHandler()) {
OnPopHandler* handler = frameobj->onPopHandler();
Maybe<AutoRealm> ar;
@ -2193,7 +2200,7 @@ ResumeMode Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled,
if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
Debugger* dbg = *p;
if (hookIsEnabled(dbg)) {
if (dbg->enabled && hookIsEnabled(dbg)) {
if (!triggered.append(ObjectValue(*dbg->toJSObject()))) {
return ResumeMode::Terminate;
}
@ -2214,7 +2221,7 @@ ResumeMode Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled,
for (Value* p = triggered.begin(); p != triggered.end(); p++) {
Debugger* dbg = Debugger::fromJSObject(&p->toObject());
EnterDebuggeeNoExecute nx(cx, *dbg, adjqi);
if (dbg->debuggees.has(global) && hookIsEnabled(dbg)) {
if (dbg->debuggees.has(global) && dbg->enabled && hookIsEnabled(dbg)) {
ResumeMode resumeMode = fireHook(dbg);
adjqi.runJobs();
if (resumeMode != ResumeMode::Continue) {
@ -2326,8 +2333,8 @@ ResumeMode DebugAPI::onTrap(JSContext* cx, MutableHandleValue vp) {
continue;
}
// There are two reasons we have to check whether dbg is debugging
// global.
// There are two reasons we have to check whether dbg is enabled and
// debugging global.
//
// One is just that one breakpoint handler can disable other Debuggers
// or remove debuggees.
@ -2336,7 +2343,8 @@ ResumeMode DebugAPI::onTrap(JSContext* cx, MutableHandleValue vp) {
// specific global--until they are executed. Only now do we know which
// global the script is running against.
Debugger* dbg = bp->debugger;
if (dbg->debuggees.has(global)) {
bool hasDebuggee = dbg->enabled && dbg->debuggees.has(global);
if (hasDebuggee) {
Maybe<AutoRealm> ar;
ar.emplace(cx, dbg->object);
EnterDebuggeeNoExecute nx(cx, *dbg, adjqi);
@ -2635,7 +2643,7 @@ Maybe<double> DebugAPI::allocationSamplingProbability(GlobalObject* global) {
// this is safe as long as dbgp does not escape.
Debugger* dbgp = p->unbarrieredGet();
if (dbgp->trackingAllocationSites) {
if (dbgp->trackingAllocationSites && dbgp->enabled) {
foundAnyDebuggers = true;
probability = std::max(dbgp->allocationSamplingProbability, probability);
}
@ -2671,7 +2679,7 @@ bool DebugAPI::slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj,
// such that the vector gets reallocated.
MOZ_ASSERT(dbgs.begin() == begin);
if ((*dbgp)->trackingAllocationSites &&
if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled &&
!(*dbgp)->appendAllocationSite(cx, obj, frame, when)) {
return false;
}
@ -2689,7 +2697,7 @@ bool Debugger::isDebuggeeUnbarriered(const Realm* realm) const {
bool Debugger::appendAllocationSite(JSContext* cx, HandleObject obj,
HandleSavedFrame frame,
mozilla::TimeStamp when) {
MOZ_ASSERT(trackingAllocationSites);
MOZ_ASSERT(trackingAllocationSites && enabled);
AutoRealm ar(cx, object);
RootedObject wrappedFrame(cx, frame);
@ -3216,21 +3224,21 @@ bool Debugger::hookObservesAllExecution(Hook which) {
}
Debugger::IsObserving Debugger::observesAllExecution() const {
if (!!getHook(OnEnterFrame)) {
if (enabled && !!getHook(OnEnterFrame)) {
return Observing;
}
return NotObserving;
}
Debugger::IsObserving Debugger::observesAsmJS() const {
if (!allowUnobservedAsmJS) {
if (enabled && !allowUnobservedAsmJS) {
return Observing;
}
return NotObserving;
}
Debugger::IsObserving Debugger::observesCoverage() const {
if (collectCoverageInfo) {
if (enabled && collectCoverageInfo) {
return Observing;
}
return NotObserving;
@ -3347,7 +3355,7 @@ bool DebugAPI::isObservedByDebuggerTrackingAllocations(
// Use unbarrieredGet() to prevent triggering read barrier while
// collecting, this is safe as long as dbg does not escape.
Debugger* dbg = p->unbarrieredGet();
if (dbg->trackingAllocationSites) {
if (dbg->trackingAllocationSites && dbg->enabled) {
return true;
}
}
@ -3754,6 +3762,71 @@ static Debugger* Debugger_fromThisValue(JSContext* cx, const CallArgs& args,
Debugger* dbg = Debugger_fromThisValue(cx, args, fnname); \
if (!dbg) return false
/* static */
bool Debugger::getEnabled(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER(cx, argc, vp, "get enabled", args, dbg);
args.rval().setBoolean(dbg->enabled);
return true;
}
/* static */
bool Debugger::setEnabled(JSContext* cx, unsigned argc, Value* vp) {
THIS_DEBUGGER(cx, argc, vp, "set enabled", args, dbg);
if (!args.requireAtLeast(cx, "Debugger.set enabled", 1)) {
return false;
}
bool wasEnabled = dbg->enabled;
dbg->enabled = ToBoolean(args[0]);
if (wasEnabled != dbg->enabled) {
if (dbg->trackingAllocationSites) {
if (wasEnabled) {
dbg->removeAllocationsTrackingForAllDebuggees();
} else {
if (!dbg->addAllocationsTrackingForAllDebuggees(cx)) {
dbg->enabled = false;
return false;
}
}
}
for (Breakpoint* bp = dbg->firstBreakpoint(); bp;
bp = bp->nextInDebugger()) {
if (!wasEnabled) {
bp->site->inc(cx->runtime()->defaultFreeOp());
} else {
bp->site->dec(cx->runtime()->defaultFreeOp());
}
}
// Add or remove ourselves from the runtime's list of Debuggers
// that care about new globals.
if (dbg->getHook(OnNewGlobalObject)) {
if (!wasEnabled) {
cx->runtime()->onNewGlobalObjectWatchers().pushBack(dbg);
} else {
cx->runtime()->onNewGlobalObjectWatchers().remove(dbg);
}
}
// Ensure the compartment is observable if we are re-enabling a
// Debugger with hooks that observe all execution.
if (!dbg->updateObservesAllExecutionOnDebuggees(
cx, dbg->observesAllExecution())) {
return false;
}
// Note: To toogle code coverage, we currently need to have no live
// stack frame, thus the coverage does not depend on the enabled flag.
dbg->updateObservesAsmJSOnDebuggees(dbg->observesAsmJS());
}
args.rval().setUndefined();
return true;
}
/* static */
bool Debugger::getHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg,
Hook which) {
@ -3881,11 +3954,13 @@ bool Debugger::setOnNewGlobalObject(JSContext* cx, unsigned argc, Value* vp) {
// Add or remove ourselves from the runtime's list of Debuggers that care
// about new globals.
JSObject* newHook = dbg->getHook(OnNewGlobalObject);
if (!oldHook && newHook) {
cx->runtime()->onNewGlobalObjectWatchers().pushBack(dbg);
} else if (oldHook && !newHook) {
cx->runtime()->onNewGlobalObjectWatchers().remove(dbg);
if (dbg->enabled) {
JSObject* newHook = dbg->getHook(OnNewGlobalObject);
if (!oldHook && newHook) {
cx->runtime()->onNewGlobalObjectWatchers().pushBack(dbg);
} else if (oldHook && !newHook) {
cx->runtime()->onNewGlobalObjectWatchers().remove(dbg);
}
}
return true;
@ -4413,13 +4488,13 @@ bool Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global) {
});
// (5)
if (trackingAllocationSites &&
if (trackingAllocationSites && enabled &&
!Debugger::addAllocationsTracking(cx, global)) {
return false;
}
auto allocationsTrackingGuard = MakeScopeExit([&] {
if (trackingAllocationSites) {
if (trackingAllocationSites && enabled) {
Debugger::removeAllocationsTracking(*global);
}
});
@ -5846,6 +5921,7 @@ bool Debugger::adoptSource(JSContext* cx, unsigned argc, Value* vp) {
}
const JSPropertySpec Debugger::properties[] = {
JS_PSGS("enabled", Debugger::getEnabled, Debugger::setEnabled, 0),
JS_PSGS("onDebuggerStatement", Debugger::getOnDebuggerStatement,
Debugger::setOnDebuggerStatement, 0),
JS_PSGS("onExceptionUnwind", Debugger::getOnExceptionUnwind,
@ -6038,13 +6114,16 @@ bool Debugger::observesFrame(const FrameIter& iter) const {
}
bool Debugger::observesScript(JSScript* script) const {
if (!enabled) {
return false;
}
// Don't ever observe self-hosted scripts: the Debugger API can break
// self-hosted invariants.
return observesGlobal(&script->global()) && !script->selfHosted();
}
bool Debugger::observesWasm(wasm::Instance* instance) const {
if (!instance->debugEnabled()) {
if (!enabled || !instance->debugEnabled()) {
return false;
}
return observesGlobal(&instance->object()->global());
@ -7157,7 +7236,7 @@ JS_PUBLIC_API bool FireOnGarbageCollectionHookRequired(JSContext* cx) {
AutoCheckCannotGC noGC;
for (Debugger* dbg : cx->runtime()->debuggerList()) {
if (dbg->observedGC(cx->runtime()->gc.majorGCCount()) &&
if (dbg->enabled && dbg->observedGC(cx->runtime()->gc.majorGCCount()) &&
dbg->getHook(Debugger::OnGarbageCollection)) {
return true;
}
@ -7177,7 +7256,7 @@ JS_PUBLIC_API bool FireOnGarbageCollectionHook(
AutoCheckCannotGC noGC;
for (Debugger* dbg : cx->runtime()->debuggerList()) {
if (dbg->observedGC(data->majorGCNumber()) &&
if (dbg->enabled && dbg->observedGC(data->majorGCNumber()) &&
dbg->getHook(Debugger::OnGarbageCollection)) {
if (!triggered.append(dbg->object)) {
JS_ReportOutOfMemory(cx);

View File

@ -243,8 +243,8 @@ extern void CheckDebuggeeThing(JSObject* obj, bool invisibleOk);
* not, because they are not deleted when a compartment is no longer a
* debuggee: the values need to maintain object identity across add/remove/add
* transitions. (Frames are an exception to the rule. Existing Debugger.Frame
* objects are killed if their realm is removed as a debugger; if the realm
* beacomes a debuggee again later, new Frame objects are created.)
* objects are killed when debugging is disabled for their compartment, and if
* it's re-enabled later, new Frame objects are created.)
*/
template <class UnbarrieredKey, bool InvisibleKeysOk = false>
class DebuggerWeakMap
@ -445,6 +445,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
return observedGCs.put(majorGCNumber);
}
bool isEnabled() const { return enabled; }
static SavedFrame* getObjectAllocationSite(JSObject& obj);
struct AllocationsLogEntry {
@ -490,6 +492,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
debuggees; /* Debuggee globals. Cross-compartment weak references. */
JS::ZoneSet debuggeeZones; /* Set of zones that we have debuggees in. */
js::GCPtrObject uncaughtExceptionHook; /* Strong reference. */
bool enabled;
bool allowUnobservedAsmJS;
// Whether to enable code coverage on the Debuggee.
@ -543,7 +546,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
/*
* Add allocations tracking for objects allocated within the given
* debuggee's compartment. The given debuggee global must be observed by at
* least one Debugger that is tracking allocations.
* least one Debugger that is enabled and tracking allocations.
*/
static MOZ_MUST_USE bool addAllocationsTracking(
JSContext* cx, Handle<GlobalObject*> debuggee);
@ -562,7 +565,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
void removeAllocationsTrackingForAllDebuggees();
/*
* If this Debugger has a onNewGlobalObject handler, then
* If this Debugger is enabled, and has a onNewGlobalObject handler, then
* this link is inserted into the list headed by
* JSRuntime::onNewGlobalObjectWatchers.
*/
@ -599,10 +602,9 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
* onEnterFrame handler on resume, and to retain onStep and onPop hooks.
*
* An entry is present in this table when:
* - both the debuggee generator object and the Debugger.Frame object exists
* - the debuggee generator object belongs to a relam that is a debuggee of
* the Debugger.Frame's owner.
*
* - both the debuggee generator object and the Debugger.Frame object exist
* - the Debugger.Frame's owner is still an enabled debugger of
* the debuggee compartment
* regardless of whether the frame is currently suspended. (This list is
* meant to explain why we update the table in the particular places where
* we do so.)
@ -773,6 +775,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger> {
static MOZ_MUST_USE bool setHookImpl(JSContext* cx, CallArgs& args,
Debugger& dbg, Hook which);
static bool getEnabled(JSContext* cx, unsigned argc, Value* vp);
static bool setEnabled(JSContext* cx, unsigned argc, Value* vp);
static bool getOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp);
static bool setOnDebuggerStatement(JSContext* cx, unsigned argc, Value* vp);
static bool getOnExceptionUnwind(JSContext* cx, unsigned argc, Value* vp);
@ -1225,7 +1229,7 @@ class BreakpointSite {
* site's list.
*
* GC rules:
* - script is live and breakpoint exists
* - script is live, breakpoint exists, and debugger is enabled
* ==> debugger is live
* - script is live, breakpoint exists, and debugger is live
* ==> retain the breakpoint and the handler object is live
@ -1344,12 +1348,16 @@ js::GCPtrNativeObject& Debugger::toJSObjectRef() {
return object;
}
bool Debugger::observesEnterFrame() const { return getHook(OnEnterFrame); }
bool Debugger::observesEnterFrame() const {
return enabled && getHook(OnEnterFrame);
}
bool Debugger::observesNewScript() const { return getHook(OnNewScript); }
bool Debugger::observesNewScript() const {
return enabled && getHook(OnNewScript);
}
bool Debugger::observesNewGlobalObject() const {
return getHook(OnNewGlobalObject);
return enabled && getHook(OnNewGlobalObject);
}
bool Debugger::observesGlobal(GlobalObject* global) const {

View File

@ -145,6 +145,10 @@ bool DebuggerMemory::setTrackingAllocationSites(JSContext* cx, unsigned argc,
dbg->trackingAllocationSites = enabling;
if (!dbg->enabled) {
return undefined(args);
}
if (enabling) {
if (!dbg->addAllocationsTrackingForAllDebuggees(cx)) {
dbg->trackingAllocationSites = false;
@ -333,7 +337,7 @@ bool DebuggerMemory::setAllocationSamplingProbability(JSContext* cx,
// If this is a change any debuggees would observe, have all debuggee
// realms recompute their sampling probabilities.
if (dbg->trackingAllocationSites) {
if (dbg->enabled && dbg->trackingAllocationSites) {
for (auto r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
r.front()->realm()->chooseAllocationSamplingProbability();
}

View File

@ -40,7 +40,8 @@ EnterDebuggeeNoExecute* EnterDebuggeeNoExecute::findInStack(JSContext* cx) {
for (EnterDebuggeeNoExecute* it = cx->noExecuteDebuggerTop; it;
it = it->prev_) {
Debugger& dbg = it->debugger();
if (!it->unlocked_ && dbg.observesGlobal(debuggee->maybeGlobal())) {
if (!it->unlocked_ && dbg.isEnabled() &&
dbg.observesGlobal(debuggee->maybeGlobal())) {
return it;
}
}

View File

@ -19,8 +19,8 @@ namespace js {
class LeaveDebuggeeNoExecute;
// Prevents all the debuggeee compartments of a given Debugger from executing
// scripts. Attempts to run script will throw an
// Given a Debugger instance dbg, if it is enabled, prevents all its debuggee
// compartments from executing scripts. Attempts to run script will throw an
// instance of Debugger.DebuggeeWouldRun from the topmost locked Debugger's
// compartment.
class MOZ_RAII EnterDebuggeeNoExecute {

View File

@ -21,6 +21,14 @@ assertEq(asmLink(asmCompile(asmFunStr))(), undefined);
g.dbg.allowUnobservedAsmJS = false;
assertAsmTypeFail(asmFunStr);
// Disabling the debugger should uninhibit.
g.dbg.enabled = false;
assertEq(asmLink(asmCompile(asmFunStr))(), undefined);
// Enabling it should inhibit again.
g.dbg.enabled = true;
assertAsmTypeFail(asmFunStr);
// Removing the global should lift the inhibition.
g.dbg.removeDebuggee(this);
assertEq(asmLink(asmCompile(asmFunStr))(), undefined);

View File

@ -0,0 +1,18 @@
var desc = Object.getOwnPropertyDescriptor(Debugger.prototype, "enabled");
assertEq(typeof desc.get, 'function');
assertEq(typeof desc.set, 'function');
var g = newGlobal({newCompartment: true});
var hits;
var dbg = new Debugger(g);
assertEq(dbg.enabled, true);
dbg.onDebuggerStatement = 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);
}

View File

@ -0,0 +1,17 @@
// Tests that hooks work if set while the Debugger is disabled.
var g = newGlobal({newCompartment: true});
var dbg = new Debugger(g);
var log = "";
g.eval("" + function f() { return 42; });
dbg.enabled = false;
dbg.onEnterFrame = function (frame) {
log += "1";
};
dbg.enabled = true;
g.f();
assertEq(log, "1");

View File

@ -12,3 +12,13 @@ dbg.onNewGlobalObject = function (global) {
log = '';
newGlobal();
assertEq(log, 'n');
log = '';
dbg.enabled = false;
newGlobal();
assertEq(log, '');
log = '';
dbg.enabled = true;
newGlobal();
assertEq(log, 'n');

View File

@ -9,10 +9,12 @@ var hit;
function handler(global) {
hit++;
log += hit;
if (hit == 2)
dbg1.enabled = dbg2.enabled = dbg3.enabled = false;
};
log = '';
hit = 0;
dbg1.onNewGlobalObject = dbg2.onNewGlobalObject = dbg3.onNewGlobalObject = handler;
newGlobal();
assertEq(log, '123');
assertEq(log, '12');

View File

@ -10,4 +10,8 @@ let promisesFound = [];
dbg.onNewPromise = p => { promisesFound.push(p); };
let p1 = new g.Promise(function (){});
dbg.enabled = false;
let p2 = new g.Promise(function (){});
assertEq(promisesFound.indexOf(gw.makeDebuggeeValue(p1)) != -1, true);
assertEq(promisesFound.indexOf(gw.makeDebuggeeValue(p2)) == -1, true);

View File

@ -16,3 +16,10 @@ g.settlePromiseNow(p);
assertEq(log, "s");
assertEq(pw, gw.makeDebuggeeValue(p));
log = "";
dbg.enabled = false;
p = new g.Promise(function (){});
g.settlePromiseNow(p);
assertEq(log, "");

View File

@ -0,0 +1,44 @@
// An onPop handler in a disabled Debugger's frame shouldn't fire.
var g = newGlobal({newCompartment: true});
var dbg = new Debugger(g);
g.eval('function f() { debugger; }');
var log;
dbg.onEnterFrame = function handleEnterFrame(f) {
log += '(';
assertEq(f.callee.name, 'f');
f.onPop = function handlePop(c) {
log += ')';
assertEq(dbg.enabled, true);
};
};
var enable;
dbg.onDebuggerStatement = function handleDebugger(f) {
dbg.enabled = enable;
}
// This should fire the onEnterFrame and onPop handlers.
log = 'a';
enable = true;
g.f();
// This should fire the onEnterFrame handler, but not the onPop.
log += 'b';
enable = false;
g.f();
// This should fire neither.
log += 'c';
dbg.enabled = false;
enable = false;
g.f();
// This should fire both again.
log += 'd';
dbg.enabled = true;
enable = true;
g.f();
assertEq(log, 'a()b(cd()');

View File

@ -0,0 +1,36 @@
// One Debugger's onPop handler can disable another Debugger.
var g = newGlobal({newCompartment: true});
var dbg1 = new Debugger(g);
var dbg2 = new Debugger(g);
var log;
var frames = [];
var firstPop = true;
function handleEnter(frame) {
log += '(';
frames.push(frame);
frame.debugger = this;
frame.onPop = function handlePop(completion) {
log += ')';
assertEq(completion.return, 42);
if (firstPop) {
// We can't say which frame's onPop handler will get called first.
if (this == frames[0])
frames[1].debugger.enabled = false;
else
frames[0].debugger.enabled = false;
} else {
assertEq("second pop handler was called",
"second pop handler should not be called");
}
firstPop = false;
};
};
dbg1.onEnterFrame = handleEnter;
dbg2.onEnterFrame = handleEnter;
log = '';
assertEq(g.eval('40 + 2'), 42);
assertEq(log, '(()');

View File

@ -0,0 +1,17 @@
// Test that disabling the debugger disables allocation tracking.
load(libdir + "asserts.js");
const dbg = new Debugger();
const root = newGlobal({newCompartment: true});
dbg.addDebuggee(root);
dbg.memory.trackingAllocationSites = true;
dbg.enabled = false;
root.eval("this.alloc = {}");
// We shouldn't accumulate allocations in our log while the debugger is
// disabled.
let allocs = dbg.memory.drainAllocationsLog();
assertEq(allocs.length, 0);

View File

@ -74,3 +74,32 @@ test("Setting trackingAllocationSites to true should throw if the debugger " +
assertEq(isTrackingAllocations(root1, d1r1), false);
assertEq(isTrackingAllocations(root2, d1r2), false);
});
test("A Debugger isn't tracking allocation sites when disabled.",
() => {
dbg1.memory.trackingAllocationSites = true;
let d1r1 = dbg1.addDebuggee(root1);
assertEq(isTrackingAllocations(root1, d1r1), true);
dbg1.enabled = false;
assertEq(isTrackingAllocations(root1, d1r1), false);
});
test("Re-enabling throws an error if we can't reinstall allocations tracking " +
"for all debuggees.",
() => {
dbg1.enabled = false
dbg1.memory.trackingAllocationSites = true;
let d1r1 = dbg1.addDebuggee(root1);
let d1r2 = dbg1.addDebuggee(root2);
// Can't install allocation hooks for root2 with this set.
root2.enableShellAllocationMetadataBuilder();
assertThrowsInstanceOf(() => dbg1.enabled = true,
Error);
assertEq(dbg1.enabled, false);
assertEq(isTrackingAllocations(root1, d1r1), false);
assertEq(isTrackingAllocations(root2, d1r2), false);
});

View File

@ -0,0 +1,21 @@
// Disabling a Debugger object causes events to stop being delivered to it
// immediately, even if we're in the middle of dispatching.
var g = newGlobal({newCompartment: true});
var log;
var arr = [];
for (var i = 0; i < 4; i++) {
arr[i] = new Debugger(g);
arr[i].num = i;
arr[i].onDebuggerStatement = 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');

View File

@ -22,6 +22,10 @@ var handlers = [() => { g.f(); },
function testHookEnabled(hookName, trigger) {
for (var h of handlers) {
assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
dbg.enabled = false;
h();
dbg.enabled = true;
assertThrowsInstanceOf(h, Debugger.DebuggeeWouldRun);
}
}

View File

@ -34,7 +34,7 @@ function test(mode, expected) {
log += x;
`);
assertEq(g.log, expected);
dbg.removeDebuggee(g);
dbg.enabled = false;
}
// We fire onEnterFrame for the initial activation when a generator is first

View File

@ -65,7 +65,7 @@ function run_test() {
ok(debuggeree.fired >= 1);
ok(fired >= 1);
debuggeree.dbg.removeAllDebuggees();
debuggeree.dbg.enabled = dbg.enabled = false;
do_test_finished();
});
});