зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1176880 part 1 - Add a flag on the Debugger & Compartment to record code-coverage information. r=shu
This commit is contained in:
Родитель
02eebef322
Коммит
b2aebab5f5
|
@ -308,22 +308,6 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc, TraceOrMarkRuntime traceOrMark)
|
|||
for (ContextIter acx(rt); !acx.done(); acx.next())
|
||||
acx->mark(trc);
|
||||
|
||||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
if (traceOrMark == MarkRuntime && !zone->isCollecting())
|
||||
continue;
|
||||
|
||||
/* Do not discard scripts with counts while profiling. */
|
||||
if (rt->profilingScripts && !rt->isHeapMinorCollecting()) {
|
||||
for (ZoneCellIterUnderGC i(zone, AllocKind::SCRIPT); !i.done(); i.next()) {
|
||||
JSScript* script = i.get<JSScript>();
|
||||
if (script->hasScriptCounts()) {
|
||||
TraceRoot(trc, &script, "profilingScripts");
|
||||
MOZ_ASSERT(script == i.get<JSScript>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
c->traceRoots(trc, traceOrMark);
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
// This script check that when we enable / disable the code coverage collection,
|
||||
// then we have different results for the getOffsetsCoverage methods.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var coverageInfo = [];
|
||||
var num = 20;
|
||||
function loop(i) {
|
||||
var n = 0;
|
||||
for (n = 0; n < i; n++)
|
||||
debugger;
|
||||
}
|
||||
g.eval(loop.toSource());
|
||||
|
||||
dbg.onDebuggerStatement = function (f) {
|
||||
// Collect coverage info each time we hit a debugger statement.
|
||||
coverageInfo.push(f.callee.script.getOffsetsCoverage());
|
||||
};
|
||||
|
||||
coverageInfo = [];
|
||||
dbg.collectCoverageInfo = false;
|
||||
g.eval("loop(" + num + ");");
|
||||
assertEq(coverageInfo.length, num);
|
||||
assertEq(coverageInfo[0], null);
|
||||
assertEq(coverageInfo[num - 1], null);
|
||||
|
||||
coverageInfo = [];
|
||||
dbg.collectCoverageInfo = true;
|
||||
g.eval("loop(" + num + ");");
|
||||
assertEq(coverageInfo.length, num);
|
||||
assertEq(!coverageInfo[0], false);
|
||||
assertEq(!coverageInfo[num - 1], false);
|
||||
|
||||
coverageInfo = [];
|
||||
dbg.collectCoverageInfo = false;
|
||||
g.eval("loop(" + num + ");");
|
||||
assertEq(coverageInfo.length, num);
|
||||
assertEq(coverageInfo[0], null);
|
||||
assertEq(coverageInfo[num - 1], null);
|
|
@ -0,0 +1,21 @@
|
|||
// |jit-test| error: Error: can't start debugging: a debuggee script is on the stack
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
function loop(i) {
|
||||
var n = 0;
|
||||
for (n = 0; n < i; n++)
|
||||
debugger;
|
||||
}
|
||||
g.eval(loop.toSource());
|
||||
|
||||
var countDown = 20;
|
||||
dbg.onDebuggerStatement = function (f) {
|
||||
// Should throw an error.
|
||||
if (countDown > 0 && --countDown == 0) {
|
||||
dbg.collectCoverageInfo = !dbg.collectCoverageInfo;
|
||||
}
|
||||
};
|
||||
|
||||
dbg.collectCoverageInfo = false;
|
||||
g.eval("loop("+ (2 * countDown) +");");
|
|
@ -0,0 +1,22 @@
|
|||
// |jit-test| error: Error: can't start debugging: a debuggee script is on the stack
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
|
||||
function loop(i) {
|
||||
var n = 0;
|
||||
for (n = 0; n < i; n++)
|
||||
debugger;
|
||||
}
|
||||
g.eval(loop.toSource());
|
||||
|
||||
var countDown = 20;
|
||||
dbg.onDebuggerStatement = function (f) {
|
||||
// Should throw an error.
|
||||
if (countDown > 0 && --countDown == 0) {
|
||||
dbg.collectCoverageInfo = !dbg.collectCoverageInfo;
|
||||
}
|
||||
};
|
||||
|
||||
dbg.collectCoverageInfo = true;
|
||||
g.eval("loop("+ (2 * countDown) +");");
|
|
@ -0,0 +1,24 @@
|
|||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
function f(x) {
|
||||
while (x) {
|
||||
interruptIf(true);
|
||||
x -= 1;
|
||||
}
|
||||
}
|
||||
g.eval(f.toSource());
|
||||
|
||||
// Toogle the debugger while the function f is running.
|
||||
setInterruptCallback(toogleDebugger);
|
||||
function toogleDebugger() {
|
||||
dbg.enabled = !dbg.enabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
dbg.collectCoverageInfo = false;
|
||||
dbg.enabled = false;
|
||||
g.eval("f(10);");
|
||||
|
||||
dbg.collectCoverageInfo = true;
|
||||
dbg.enabled = false;
|
||||
g.eval("f(10);");
|
|
@ -91,6 +91,12 @@ BaselineCompiler::compile()
|
|||
if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
|
||||
return Method_Error;
|
||||
|
||||
// When a Debugger set the collectCoverageInfo flag, we recompile baseline
|
||||
// scripts without entering the interpreter again. We have to create the
|
||||
// ScriptCounts if they do not exist.
|
||||
if (!script->hasScriptCounts() && cx->compartment()->collectCoverage())
|
||||
script->initScriptCounts(cx);
|
||||
|
||||
// Pin analysis info during compilation.
|
||||
AutoEnterAnalysis autoEnterAnalysis(cx);
|
||||
|
||||
|
|
|
@ -568,6 +568,16 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
|
|||
|
||||
if (objectMetadataTable)
|
||||
objectMetadataTable->trace(trc);
|
||||
|
||||
if (scriptCountsMap && !trc->runtime()->isHeapMinorCollecting()) {
|
||||
MOZ_ASSERT_IF(!trc->runtime()->isBeingDestroyed(), collectCoverage());
|
||||
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
|
||||
JSScript* script = const_cast<JSScript*>(r.front().key());
|
||||
MOZ_ASSERT(script->hasScriptCounts());
|
||||
TraceRoot(trc, &script, "profilingScripts");
|
||||
MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -925,14 +935,15 @@ JSCompartment::updateDebuggerObservesFlag(unsigned flag)
|
|||
{
|
||||
MOZ_ASSERT(isDebuggee());
|
||||
MOZ_ASSERT(flag == DebuggerObservesAllExecution ||
|
||||
flag == DebuggerObservesCoverage ||
|
||||
flag == DebuggerObservesAsmJS);
|
||||
|
||||
const GlobalObject::DebuggerVector* v = maybeGlobal()->getDebuggers();
|
||||
for (Debugger * const* p = v->begin(); p != v->end(); p++) {
|
||||
Debugger* dbg = *p;
|
||||
if (flag == DebuggerObservesAllExecution
|
||||
? dbg->observesAllExecution()
|
||||
: dbg->observesAsmJS())
|
||||
if (flag == DebuggerObservesAllExecution ? dbg->observesAllExecution() :
|
||||
flag == DebuggerObservesCoverage ? dbg->observesCoverage() :
|
||||
dbg->observesAsmJS())
|
||||
{
|
||||
debugModeBits |= flag;
|
||||
return;
|
||||
|
@ -951,6 +962,49 @@ JSCompartment::unsetIsDebuggee()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::updateDebuggerObservesCoverage()
|
||||
{
|
||||
bool previousState = debuggerObservesCoverage();
|
||||
updateDebuggerObservesFlag(DebuggerObservesCoverage);
|
||||
if (previousState == debuggerObservesCoverage())
|
||||
return;
|
||||
|
||||
if (debuggerObservesCoverage()) {
|
||||
// Interrupt any running interpreter frame. The scriptCounts are
|
||||
// allocated on demand when a script resume its execution.
|
||||
for (ActivationIterator iter(runtimeFromMainThread()); !iter.done(); ++iter) {
|
||||
if (iter->isInterpreter())
|
||||
iter->asInterpreter()->enableInterruptsUnconditionally();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If the runtime flag is enabled, then keep the data until
|
||||
// StopPCCountProfiling is called.
|
||||
if (runtimeFromMainThread()->profilingScripts)
|
||||
return;
|
||||
|
||||
clearScriptCounts();
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::clearScriptCounts()
|
||||
{
|
||||
if (!scriptCountsMap)
|
||||
return;
|
||||
|
||||
// Clear all hasScriptCounts_ flags of JSScript, in order to release all
|
||||
// ScriptCounts entry of the current compartment.
|
||||
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
|
||||
ScriptCounts* value = &r.front().value();
|
||||
r.front().key()->takeOverScriptCountsMapEntry(value);
|
||||
}
|
||||
|
||||
js_delete(scriptCountsMap);
|
||||
scriptCountsMap = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::clearBreakpointsIn(FreeOp* fop, js::Debugger* dbg, HandleObject handler)
|
||||
{
|
||||
|
|
|
@ -465,13 +465,15 @@ struct JSCompartment
|
|||
IsDebuggee = 1 << 0,
|
||||
DebuggerObservesAllExecution = 1 << 1,
|
||||
DebuggerObservesAsmJS = 1 << 2,
|
||||
DebuggerNeedsDelazification = 1 << 3
|
||||
DebuggerObservesCoverage = 1 << 3,
|
||||
DebuggerNeedsDelazification = 1 << 4
|
||||
};
|
||||
|
||||
unsigned debugModeBits;
|
||||
|
||||
static const unsigned DebuggerObservesMask = IsDebuggee |
|
||||
DebuggerObservesAllExecution |
|
||||
DebuggerObservesCoverage |
|
||||
DebuggerObservesAsmJS;
|
||||
|
||||
void updateDebuggerObservesFlag(unsigned flag);
|
||||
|
@ -652,6 +654,22 @@ struct JSCompartment
|
|||
updateDebuggerObservesFlag(DebuggerObservesAsmJS);
|
||||
}
|
||||
|
||||
// True if this compartment's global is a debuggee of some Debugger object
|
||||
// whose collectCoverageInfo flag is true.
|
||||
bool debuggerObservesCoverage() const {
|
||||
static const unsigned Mask = DebuggerObservesCoverage;
|
||||
return (debugModeBits & Mask) == Mask;
|
||||
}
|
||||
void updateDebuggerObservesCoverage();
|
||||
|
||||
// The code coverage can be enabled either for each compartment, with the
|
||||
// Debugger API, or for the entire runtime.
|
||||
bool collectCoverage() const {
|
||||
return debuggerObservesCoverage() ||
|
||||
runtimeFromAnyThread()->profilingScripts;
|
||||
}
|
||||
void clearScriptCounts();
|
||||
|
||||
bool needsDelazificationForDebugger() const {
|
||||
return debugModeBits & DebuggerNeedsDelazification;
|
||||
}
|
||||
|
|
|
@ -1455,6 +1455,16 @@ JSScript::getIonCounts()
|
|||
return getScriptCounts().ionCounts_;
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::takeOverScriptCountsMapEntry(ScriptCounts* entryValue)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
|
||||
MOZ_ASSERT(entryValue == &p->value());
|
||||
#endif
|
||||
hasScriptCounts_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::releaseScriptCounts(ScriptCounts* counts)
|
||||
{
|
||||
|
|
|
@ -1639,6 +1639,8 @@ class JSScript : public js::gc::TenuredCell
|
|||
js::jit::IonScriptCounts* getIonCounts();
|
||||
void releaseScriptCounts(js::ScriptCounts* counts);
|
||||
void destroyScriptCounts(js::FreeOp* fop);
|
||||
// The entry should be removed after using this function.
|
||||
void takeOverScriptCountsMapEntry(js::ScriptCounts* entryValue);
|
||||
|
||||
jsbytecode* main() {
|
||||
return code() + mainOffset();
|
||||
|
|
|
@ -358,6 +358,7 @@ Debugger::Debugger(JSContext* cx, NativeObject* dbg)
|
|||
uncaughtExceptionHook(nullptr),
|
||||
enabled(true),
|
||||
allowUnobservedAsmJS(false),
|
||||
collectCoverageInfo(false),
|
||||
observedGCs(cx),
|
||||
tenurePromotionsLog(cx),
|
||||
trackingTenurePromotions(false),
|
||||
|
@ -1841,6 +1842,9 @@ class MOZ_RAII ExecutionObservableCompartments : public Debugger::ExecutionObser
|
|||
bool init() { return compartments_.init() && zones_.init(); }
|
||||
bool add(JSCompartment* comp) { return compartments_.put(comp) && zones_.put(comp->zone()); }
|
||||
|
||||
typedef HashSet<JSCompartment*>::Range CompartmentRange;
|
||||
const HashSet<JSCompartment*>* compartments() const { return &compartments_; }
|
||||
|
||||
const HashSet<Zone*>* zones() const { return &zones_; }
|
||||
bool shouldRecompileOrInvalidate(JSScript* script) const {
|
||||
return script->hasBaselineScript() && compartments_.has(script->compartment());
|
||||
|
@ -2185,6 +2189,14 @@ Debugger::observesAsmJS() const
|
|||
return NotObserving;
|
||||
}
|
||||
|
||||
Debugger::IsObserving
|
||||
Debugger::observesCoverage() const
|
||||
{
|
||||
if (enabled && collectCoverageInfo)
|
||||
return Observing;
|
||||
return NotObserving;
|
||||
}
|
||||
|
||||
// Toggle whether this Debugger's debuggees observe all execution. This is
|
||||
// called when a hook that observes all execution is set or unset. See
|
||||
// hookObservesAllExecution.
|
||||
|
@ -2213,6 +2225,53 @@ Debugger::updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving obser
|
|||
return updateExecutionObservability(cx, obs, observing);
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing)
|
||||
{
|
||||
ExecutionObservableCompartments obs(cx);
|
||||
if (!obs.init())
|
||||
return false;
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject* global = r.front();
|
||||
JSCompartment* comp = global->compartment();
|
||||
|
||||
if (comp->debuggerObservesCoverage() == observing)
|
||||
continue;
|
||||
|
||||
// Invalidate and recompile a compartment to add or remove PCCounts
|
||||
// increments. We have to eagerly invalidate, as otherwise we might have
|
||||
// dangling pointers to freed PCCounts.
|
||||
if (!obs.add(comp))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If any frame on the stack belongs to the debuggee, then we cannot update
|
||||
// the ScriptCounts, because this would imply to invalidate a Debugger.Frame
|
||||
// to recompile it with/without ScriptCount support.
|
||||
for (ScriptFrameIter iter(cx, ScriptFrameIter::ALL_CONTEXTS,
|
||||
ScriptFrameIter::GO_THROUGH_SAVED);
|
||||
!iter.done();
|
||||
++iter)
|
||||
{
|
||||
if (obs.shouldMarkAsDebuggee(iter)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!updateExecutionObservability(cx, obs, observing))
|
||||
return false;
|
||||
|
||||
// All compartments can safely be toggled, and all scripts will be
|
||||
// recompiled. Thus we can update each compartment accordingly.
|
||||
typedef ExecutionObservableCompartments::CompartmentRange CompartmentRange;
|
||||
for (CompartmentRange r = obs.compartments()->all(); !r.empty(); r.popFront())
|
||||
r.front()->updateDebuggerObservesCoverage();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::updateObservesAsmJSOnDebuggees(IsObserving observing)
|
||||
{
|
||||
|
@ -2694,6 +2753,9 @@ Debugger::setEnabled(JSContext* cx, unsigned argc, Value* vp)
|
|||
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());
|
||||
}
|
||||
|
||||
|
@ -2902,6 +2964,30 @@ Debugger::setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Debugger::getCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "get collectCoverageInfo", args, dbg);
|
||||
args.rval().setBoolean(dbg->collectCoverageInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Debugger::setCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "set collectCoverageInfo", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.set collectCoverageInfo", 1))
|
||||
return false;
|
||||
dbg->collectCoverageInfo = ToBoolean(args[0]);
|
||||
|
||||
IsObserving observing = dbg->collectCoverageInfo ? Observing : NotObserving;
|
||||
if (!dbg->updateObservesCoverageOnDebuggees(cx, observing))
|
||||
return false;
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Debugger::getMemory(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -3339,6 +3425,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
|||
// (6)
|
||||
debuggeeCompartment->setIsDebuggee();
|
||||
debuggeeCompartment->updateDebuggerObservesAsmJS();
|
||||
debuggeeCompartment->updateDebuggerObservesCoverage();
|
||||
if (observesAllExecution() && !ensureExecutionObservabilityOfCompartment(cx, debuggeeCompartment))
|
||||
return false;
|
||||
|
||||
|
@ -3453,6 +3540,7 @@ Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
|
|||
} else {
|
||||
global->compartment()->updateDebuggerObservesAllExecution();
|
||||
global->compartment()->updateDebuggerObservesAsmJS();
|
||||
global->compartment()->updateDebuggerObservesCoverage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4433,6 +4521,8 @@ const JSPropertySpec Debugger::properties[] = {
|
|||
Debugger::setUncaughtExceptionHook, 0),
|
||||
JS_PSGS("allowUnobservedAsmJS", Debugger::getAllowUnobservedAsmJS,
|
||||
Debugger::setAllowUnobservedAsmJS, 0),
|
||||
JS_PSGS("collectCoverageInfo", Debugger::getCollectCoverageInfo,
|
||||
Debugger::setCollectCoverageInfo, 0),
|
||||
JS_PSG("memory", Debugger::getMemory, 0),
|
||||
JS_PSGS("onIonCompilation", Debugger::getOnIonCompilation, Debugger::setOnIonCompilation, 0),
|
||||
JS_PS_END
|
||||
|
|
|
@ -340,6 +340,10 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
js::HeapPtrObject uncaughtExceptionHook; /* Strong reference. */
|
||||
bool enabled;
|
||||
bool allowUnobservedAsmJS;
|
||||
|
||||
// Wether to enable code coverage on the Debuggee.
|
||||
bool collectCoverageInfo;
|
||||
|
||||
JSCList breakpoints; /* Circular list of all js::Breakpoints in this debugger */
|
||||
|
||||
// The set of GC numbers for which one or more of this Debugger's observed
|
||||
|
@ -545,6 +549,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
static bool setUncaughtExceptionHook(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool getAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool getCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool setCollectCoverageInfo(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool getMemory(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool getOnIonCompilation(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool setOnIonCompilation(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
@ -594,6 +600,10 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
// execution of its debuggees.
|
||||
IsObserving observesAsmJS() const;
|
||||
|
||||
// Whether the Debugger instance needs to observe coverage of any JavaScript
|
||||
// execution.
|
||||
IsObserving observesCoverage() const;
|
||||
|
||||
private:
|
||||
static bool ensureExecutionObservabilityOfFrame(JSContext* cx, AbstractFramePtr frame);
|
||||
static bool ensureExecutionObservabilityOfCompartment(JSContext* cx, JSCompartment* comp);
|
||||
|
@ -601,6 +611,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
static bool hookObservesAllExecution(Hook which);
|
||||
|
||||
bool updateObservesAllExecutionOnDebuggees(JSContext* cx, IsObserving observing);
|
||||
bool updateObservesCoverageOnDebuggees(JSContext* cx, IsObserving observing);
|
||||
void updateObservesAsmJSOnDebuggees(IsObserving observing);
|
||||
|
||||
JSObject* getHook(Hook hook) const;
|
||||
|
|
|
@ -1960,7 +1960,7 @@ Interpret(JSContext* cx, RunState& state)
|
|||
MOZ_CRASH("bad Debugger::onEnterFrame status");
|
||||
}
|
||||
|
||||
if (cx->runtime()->profilingScripts)
|
||||
if (cx->compartment()->collectCoverage())
|
||||
activation.enableInterruptsUnconditionally();
|
||||
|
||||
// Enter the interpreter loop starting at the current pc.
|
||||
|
@ -1973,9 +1973,8 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
bool moreInterrupts = false;
|
||||
jsbytecode op = *REGS.pc;
|
||||
|
||||
if (cx->runtime()->profilingScripts) {
|
||||
if (!script->hasScriptCounts())
|
||||
script->initScriptCounts(cx);
|
||||
if (!script->hasScriptCounts() && cx->compartment()->collectCoverage()) {
|
||||
script->initScriptCounts(cx);
|
||||
moreInterrupts = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -379,6 +379,13 @@ JSRuntime::~JSRuntime()
|
|||
wpmap->clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear script counts map, to remove the strong reference on the
|
||||
* JSScript key.
|
||||
*/
|
||||
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
|
||||
comp->clearScriptCounts();
|
||||
|
||||
/* Clear atoms to remove GC roots and heap allocations. */
|
||||
finishAtoms();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче