Backed out 7 changesets (bug 935228, bug 936143, bug 935470, bug 933882, bug 934799) for breaking ASAN browser-chrome tests on a CLOSED TREE

Backed out changeset ae6f2151610f (bug 934799)
Backed out changeset 82495f0c5da2 (bug 934799)
Backed out changeset 77be849d81e7 (bug 935228)
Backed out changeset 555e5759fe5f (bug 935470)
Backed out changeset ce4011f33422 (bug 933882)
Backed out changeset e13e98eab890 (bug 936143)
Backed out changeset fb230c191a88 (bug 936143)
This commit is contained in:
Wes Kocher 2013-11-11 16:53:59 -08:00
parent 351ae40bdc
commit 3dbc5bd2fa
18 changed files with 214 additions and 402 deletions

View File

@ -25,6 +25,7 @@ namespace JS {
D(TOO_MUCH_MALLOC) \
D(ALLOC_TRIGGER) \
D(DEBUG_GC) \
D(DEBUG_MODE_GC) \
D(TRANSPLANT) \
D(RESET) \
D(OUT_OF_NURSERY) \

View File

@ -142,8 +142,7 @@ CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
return options.canLazilyParse &&
options.compileAndGo &&
options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
!(cx->compartment()->debugMode() &&
cx->compartment()->runtimeFromAnyThread()->debugHooks.newScriptHook);
!cx->compartment()->debugMode();
}
void

View File

@ -1757,9 +1757,7 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext *cx)
RootedFunction function(cx, script->function());
CallNewScriptHook(cx->asJSContext(), script, function);
// Lazy scripts are never top level (despite always being invoked with a
// nullptr parent), and so the hook should never be fired.
if (emitterMode != LazyFunction && !parent) {
if (!parent) {
GlobalObject *compileAndGoGlobal = nullptr;
if (script->compileAndGo)
compileAndGoGlobal = &script->global();

View File

@ -2121,9 +2121,6 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
// Advance this parser over tokens processed by the syntax parser.
parser->tokenStream.tell(&position);
tokenStream.seek(position, parser->tokenStream);
// Update the end position of the parse node.
pn->pn_pos.end = tokenStream.currentToken().pos.end;
}
if (!addFreeVariablesFromLazyFunction(fun, pc))

View File

@ -1,22 +0,0 @@
// Lazy scripts should correctly report line offsets
var g = newGlobal();
var dbg = new Debugger();
g.eval("// Header comment\n" + // <- line 6 in this file
"\n" +
"\n" +
"function f(n) {\n" + // <- line 9 in this file
" var foo = '!';\n" +
"}");
dbg.addDebuggee(g);
var scripts = dbg.findScripts();
var found = false;
for (var i = 0; i < scripts.length; i++) {
found = found || scripts[i].startLine == 6;
// Nothing should have offsets for the deffun on line 9 if lazy scripts
// correctly update the position.
assertEq(scripts[i].getLineOffsets(9).length, 0);
}
assertEq(found, true);

View File

@ -8,11 +8,9 @@ dbg.onDebuggerStatement = function (frame) {
assertEq(typeof frame.script.url, 'string');
};
function test(f, manualCount) {
function test(f) {
start = count = g.first = g.last = undefined;
f();
if (manualCount)
g.last = g.first + manualCount - 1;
assertEq(start, g.first);
assertEq(count, g.last + 1 - g.first);
print(start, count);
@ -43,19 +41,3 @@ g.eval("function f2() {\n" +
"}\n");
test(g.f2);
test(g.f2);
// Having a last = Error().lineNumber forces a setline srcnote, so test a
// function that ends with newline srcnotes.
g.eval("/* Any copyright is dedicated to the Public Domain.\n" +
" http://creativecommons.org/publicdomain/zero/1.0/ */\n" +
"\n" +
"function secondCall() { first = Error().lineNumber;\n" +
" debugger;\n" +
" // Comment\n" +
" eval(\"42;\");\n" +
" function foo() {}\n" +
" if (true) {\n" +
" foo();\n" + // <- this is +6 and must be within the extent
" }\n" +
"}");
test(g.secondCall, 7);

View File

@ -251,9 +251,6 @@ BaselineCompiler::compile()
bytecodeMap[script->nTypeSets] = 0;
}
if (script->compartment()->debugMode())
baselineScript->setDebugMode();
return Method_Compiled;
}

View File

@ -746,10 +746,6 @@ BaselineScript::toggleDebugTraps(JSScript *script, jsbytecode *pc)
{
JS_ASSERT(script->baselineScript() == this);
// Only scripts compiled for debug mode have toggled calls.
if (!debugMode())
return;
SrcNoteLineScanner scanner(script->notes(), script->lineno);
JSRuntime *rt = script->runtimeFromMainThread();

View File

@ -132,11 +132,7 @@ struct BaselineScript
// Flag set when the script contains any writes to its on-stack
// (rather than call object stored) arguments.
MODIFIES_ARGUMENTS = 1 << 2,
// Flag set when compiled for use for debug mode. Handles various
// Debugger hooks and compiles toggled calls for traps.
DEBUG_MODE = 1 << 3
MODIFIES_ARGUMENTS = 1 << 2
};
private:
@ -205,13 +201,6 @@ struct BaselineScript
return flags_ & MODIFIES_ARGUMENTS;
}
void setDebugMode() {
flags_ |= DEBUG_MODE;
}
bool debugMode() const {
return flags_ & DEBUG_MODE;
}
uint32_t prologueOffset() const {
return prologueOffset_;
}

View File

@ -2354,20 +2354,15 @@ InvalidateActivation(FreeOp *fop, uint8_t *ionTop, bool invalidateAll)
IonSpew(IonSpew_Invalidate, "END invalidating activation");
}
static inline void
StopOffThreadCompilation(JSCompartment *comp)
{
if (comp->jitCompartment()) {
CancelOffThreadIonCompile(comp, nullptr);
FinishAllOffThreadCompilations(comp->jitCompartment());
}
}
void
jit::InvalidateAll(FreeOp *fop, Zone *zone)
{
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
StopOffThreadCompilation(comp);
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
if (!comp->jitCompartment())
continue;
CancelOffThreadIonCompile(comp, nullptr);
FinishAllOffThreadCompilations(comp->jitCompartment());
}
for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) {
if (iter.activation()->compartment()->zone() == zone) {
@ -2714,56 +2709,3 @@ jit::TraceIonScripts(JSTracer* trc, JSScript *script)
if (script->hasBaselineScript())
jit::BaselineScript::Trace(trc, script->baselineScript());
}
AutoDebugModeInvalidation::~AutoDebugModeInvalidation()
{
MOZ_ASSERT(!!comp_ != !!zone_);
if (needInvalidation_ == NoNeed)
return;
// Invalidate the stack if any compartments toggled from on->off, because
// we allow scripts to be on stack when turning off debug mode.
bool invalidateStack = needInvalidation_ == ToggledOff;
Zone *zone = zone_ ? zone_ : comp_->zone();
JSRuntime *rt = zone->runtimeFromMainThread();
FreeOp *fop = rt->defaultFreeOp();
if (comp_) {
StopOffThreadCompilation(comp_);
} else {
for (CompartmentsInZoneIter comp(zone_); !comp.done(); comp.next())
StopOffThreadCompilation(comp);
}
if (invalidateStack) {
jit::MarkActiveBaselineScripts(zone);
for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
JSCompartment *comp = iter.activation()->compartment();
if ((comp_ && comp_ == comp) ||
(zone_ && zone_ == comp->zone() && comp->principals))
{
IonContext ictx(rt);
AutoFlushCache afc("AutoDebugModeInvalidation", rt->jitRuntime());
IonSpew(IonSpew_Invalidate, "Invalidating frames for debug mode toggle");
InvalidateActivation(fop, iter.jitTop(), true);
}
}
}
for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if ((comp_ && script->compartment() == comp_) ||
(zone_ && script->compartment()->principals))
{
FinishInvalidation(fop, script);
FinishDiscardBaselineScript(fop, script);
script->clearAnalysis();
script->resetUseCount();
} else {
if (script->hasBaselineScript())
script->baselineScript()->resetActive();
}
}
}

View File

@ -673,20 +673,20 @@ CreateLazyScriptsForCompartment(JSContext *cx)
{
AutoObjectVector lazyFunctions(cx);
// Find all live lazy scripts in the compartment, and via them all root
// lazy functions in the compartment: those which have not been compiled
// and which have a source object, indicating that their parent has been
// compiled.
for (gc::CellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) {
LazyScript *lazy = i.get<LazyScript>();
JSFunction *fun = lazy->function();
if (fun->compartment() == cx->compartment() &&
lazy->sourceObject() && !lazy->maybeScript())
{
MOZ_ASSERT(fun->isInterpretedLazy());
MOZ_ASSERT(lazy == fun->lazyScriptOrNull());
if (!lazyFunctions.append(fun))
return false;
// Find all root lazy functions in the compartment: those which have not been
// compiled and which have a source object, indicating that their parent has
// been compiled.
for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
JSObject *obj = i.get<JSObject>();
if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
JSFunction *fun = &obj->as<JSFunction>();
if (fun->isInterpretedLazy()) {
LazyScript *lazy = fun->lazyScriptOrNull();
if (lazy && lazy->sourceObject() && !lazy->maybeScript()) {
if (!lazyFunctions.append(fun))
return false;
}
}
}
}
@ -708,24 +708,27 @@ CreateLazyScriptsForCompartment(JSContext *cx)
return false;
}
// Repoint any clones of the original functions to their new script.
for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
JSObject *obj = i.get<JSObject>();
if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
JSFunction *fun = &obj->as<JSFunction>();
if (fun->isInterpretedLazy()) {
LazyScript *lazy = fun->lazyScriptOrNull();
if (lazy && lazy->maybeScript())
fun->existingScript();
}
}
}
return true;
}
bool
JSCompartment::ensureDelazifyScriptsForDebugMode(JSContext *cx)
{
MOZ_ASSERT(cx->compartment() == this);
if ((debugModeBits & DebugNeedDelazification) && !CreateLazyScriptsForCompartment(cx))
return false;
debugModeBits &= ~DebugNeedDelazification;
return true;
}
bool
JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidation &invalidate)
JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeGC &dmgc)
{
bool enabledBefore = debugMode();
bool enabledAfter = (debugModeBits & DebugModeFromMask & ~DebugFromC) || b;
bool enabledAfter = (debugModeBits & ~unsigned(DebugFromC)) || b;
// Debug mode can be enabled only when no scripts from the target
// compartment are on the stack. It would even be incorrect to discard just
@ -744,12 +747,14 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidatio
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
return false;
}
if (enabledAfter && !CreateLazyScriptsForCompartment(cx))
return false;
}
debugModeBits = (debugModeBits & ~DebugFromC) | (b ? DebugFromC : 0);
debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0);
JS_ASSERT(debugMode() == enabledAfter);
if (enabledBefore != enabledAfter) {
updateForDebugMode(cx->runtime()->defaultFreeOp(), invalidate);
updateForDebugMode(cx->runtime()->defaultFreeOp(), dmgc);
if (!enabledAfter)
DebugScopes::onCompartmentLeaveDebugMode(this);
}
@ -757,7 +762,7 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidatio
}
void
JSCompartment::updateForDebugMode(FreeOp *fop, AutoDebugModeInvalidation &invalidate)
JSCompartment::updateForDebugMode(FreeOp *fop, AutoDebugModeGC &dmgc)
{
JSRuntime *rt = runtimeFromMainThread();
@ -767,42 +772,52 @@ JSCompartment::updateForDebugMode(FreeOp *fop, AutoDebugModeInvalidation &invali
}
#ifdef JS_ION
MOZ_ASSERT(invalidate.isFor(this));
JS_ASSERT_IF(debugMode(), !hasScriptsOnStack());
// Invalidate all JIT code since debug mode invalidates assumptions made
// by the JIT.
// When we change a compartment's debug mode, whether we're turning it
// on or off, we must always throw away all analyses: debug mode
// affects various aspects of the analysis, which then get baked into
// SSA results, which affects code generation in complicated ways. We
// must also throw away all JIT code, as its soundness depends on the
// analyses.
//
// The AutoDebugModeInvalidation argument makes sure we can't forget to
// invalidate, but it is also important not to run any scripts in this
// compartment until the invalidate is destroyed. That is the caller's
// responsibility.
invalidate.scheduleInvalidation(debugMode());
// It suffices to do a garbage collection cycle or to finish the
// ongoing GC cycle. The necessary cleanup happens in
// JSCompartment::sweep.
//
// dmgc makes sure we can't forget to GC, but it is also important not
// to run any scripts in this compartment until the dmgc is destroyed.
// That is the caller's responsibility.
if (!rt->isHeapBusy())
dmgc.scheduleGC(zone());
#endif
}
bool
JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global)
{
AutoDebugModeInvalidation invalidate(this);
return addDebuggee(cx, global, invalidate);
AutoDebugModeGC dmgc(cx->runtime());
return addDebuggee(cx, global, dmgc);
}
bool
JSCompartment::addDebuggee(JSContext *cx,
GlobalObject *globalArg,
AutoDebugModeInvalidation &invalidate)
AutoDebugModeGC &dmgc)
{
Rooted<GlobalObject*> global(cx, globalArg);
bool wasEnabled = debugMode();
if (!wasEnabled && !CreateLazyScriptsForCompartment(cx))
return false;
if (!debuggees.put(global)) {
js_ReportOutOfMemory(cx);
return false;
}
debugModeBits |= DebugFromJS;
if (!wasEnabled)
updateForDebugMode(cx->runtime()->defaultFreeOp(), invalidate);
if (!wasEnabled) {
updateForDebugMode(cx->runtime()->defaultFreeOp(), dmgc);
}
return true;
}
@ -811,14 +826,14 @@ JSCompartment::removeDebuggee(FreeOp *fop,
js::GlobalObject *global,
js::GlobalObjectSet::Enum *debuggeesEnum)
{
AutoDebugModeInvalidation invalidate(this);
return removeDebuggee(fop, global, invalidate, debuggeesEnum);
AutoDebugModeGC dmgc(fop->runtime());
return removeDebuggee(fop, global, dmgc, debuggeesEnum);
}
void
JSCompartment::removeDebuggee(FreeOp *fop,
js::GlobalObject *global,
AutoDebugModeInvalidation &invalidate,
AutoDebugModeGC &dmgc,
js::GlobalObjectSet::Enum *debuggeesEnum)
{
bool wasEnabled = debugMode();
@ -832,7 +847,7 @@ JSCompartment::removeDebuggee(FreeOp *fop,
debugModeBits &= ~DebugFromJS;
if (wasEnabled && !debugMode()) {
DebugScopes::onCompartmentLeaveDebugMode(this);
updateForDebugMode(fop, invalidate);
updateForDebugMode(fop, dmgc);
}
}
}

View File

@ -110,7 +110,7 @@ struct TypeInferenceSizes;
}
namespace js {
class AutoDebugModeInvalidation;
class AutoDebugModeGC;
class ArrayBufferObject;
class DebugScopes;
class WeakMapBase;
@ -278,13 +278,7 @@ struct JSCompartment
js::WeakMapBase *gcWeakMapList;
private:
enum {
DebugFromC = 1 << 0,
DebugFromJS = 1 << 1,
DebugNeedDelazification = 1 << 2
};
static const unsigned DebugModeFromMask = DebugFromC | DebugFromJS;
enum { DebugFromC = 1, DebugFromJS = 2 };
unsigned debugModeBits; // see debugMode() below
@ -362,49 +356,27 @@ struct JSCompartment
* by Debugger objects. Therefore debugModeBits has the DebugFromC bit set
* if the C API wants debug mode and the DebugFromJS bit set if debuggees
* is non-empty.
*
* When toggling on, DebugNeedDelazification is set to signal that
* Debugger methods which depend on seeing all scripts (like findScripts)
* need to delazify the scripts in the compartment first.
*/
bool debugMode() const {
return !!(debugModeBits & DebugModeFromMask);
}
bool debugMode() const { return !!debugModeBits; }
/* True if any scripts from this compartment are on the JS stack. */
bool hasScriptsOnStack();
/*
* Schedule the compartment to be delazified. Called from
* LazyScript::Create.
*/
void scheduleDelazificationForDebugMode() {
debugModeBits |= DebugNeedDelazification;
}
/*
* If we scheduled delazification for turning on debug mode, delazify all
* scripts.
*/
bool ensureDelazifyScriptsForDebugMode(JSContext *cx);
private:
/* This is called only when debugMode() has just toggled. */
void updateForDebugMode(js::FreeOp *fop, js::AutoDebugModeInvalidation &invalidate);
void updateForDebugMode(js::FreeOp *fop, js::AutoDebugModeGC &dmgc);
public:
js::GlobalObjectSet &getDebuggees() { return debuggees; }
bool addDebuggee(JSContext *cx, js::GlobalObject *global);
bool addDebuggee(JSContext *cx, js::GlobalObject *global,
js::AutoDebugModeInvalidation &invalidate);
js::AutoDebugModeGC &dmgc);
void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global,
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global,
js::AutoDebugModeInvalidation &invalidate,
js::AutoDebugModeGC &dmgc,
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
bool setDebugModeFromC(JSContext *cx, bool b,
js::AutoDebugModeInvalidation &invalidate);
bool setDebugModeFromC(JSContext *cx, bool b, js::AutoDebugModeGC &dmgc);
void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
void clearTraps(js::FreeOp *fop);
@ -450,56 +422,29 @@ JSRuntime::isAtomsZone(JS::Zone *zone)
}
// For use when changing the debug mode flag on one or more compartments.
// Invalidate and discard JIT code since debug mode breaks JIT assumptions.
// Do not run scripts in any compartment that is scheduled for GC using this
// object. See comment in updateForDebugMode.
//
// AutoDebugModeInvalidation has two modes: compartment or zone
// invalidation. While it is correct to always use compartment invalidation,
// if you know ahead of time you need to invalidate a whole zone, it is faster
// to invalidate the zone.
//
// Compartment invalidation only invalidates scripts belonging to that
// compartment.
//
// Zone invalidation invalidates all scripts belonging to non-special
// (i.e. those with principals) compartments of the zone.
//
// FIXME: Remove entirely once bug 716647 lands.
//
class js::AutoDebugModeInvalidation
class js::AutoDebugModeGC
{
JSCompartment *comp_;
JS::Zone *zone_;
enum {
NoNeed = 0,
ToggledOn = 1,
ToggledOff = 2
} needInvalidation_;
JSRuntime *rt;
bool needGC;
public:
explicit AutoDebugModeInvalidation(JSCompartment *comp)
: comp_(comp), zone_(nullptr), needInvalidation_(NoNeed)
{ }
explicit AutoDebugModeGC(JSRuntime *rt) : rt(rt), needGC(false) {}
explicit AutoDebugModeInvalidation(JS::Zone *zone)
: comp_(nullptr), zone_(zone), needInvalidation_(NoNeed)
{ }
~AutoDebugModeInvalidation();
bool isFor(JSCompartment *comp) {
if (comp_)
return comp == comp_;
return comp->zone() == zone_;
~AutoDebugModeGC() {
// Under some circumstances (say, in the midst of an animation),
// the garbage collector may try to retain JIT code and analyses.
// The DEBUG_MODE_GC reason forces the collector to always throw
// everything away, as required for debug mode transitions.
if (needGC)
GC(rt, GC_NORMAL, JS::gcreason::DEBUG_MODE_GC);
}
void scheduleInvalidation(bool debugMode) {
// If we are scheduling invalidation for multiple compartments, they
// must all agree on the toggle. This is so we can decide if we need
// to invalidate on-stack scripts.
MOZ_ASSERT_IF(needInvalidation_ != NoNeed,
needInvalidation_ == debugMode ? ToggledOn : ToggledOff);
needInvalidation_ = debugMode ? ToggledOn : ToggledOff;
void scheduleGC(Zone *zone) {
JS_ASSERT(!rt->isHeapBusy());
PrepareZoneForGC(zone);
needGC = true;
}
};

View File

@ -4620,8 +4620,13 @@ ShouldCleanUpEverything(JSRuntime *rt, JS::gcreason::Reason reason, JSGCInvocati
// During shutdown, we must clean everything up, for the sake of leak
// detection. When a runtime has no contexts, or we're doing a GC before a
// shutdown CC, those are strong indications that we're shutting down.
//
// DEBUG_MODE_GC indicates we're discarding code because the debug mode
// has changed; debug mode affects the results of bytecode analysis, so
// we need to clear everything away.
return reason == JS::gcreason::DESTROY_RUNTIME ||
reason == JS::gcreason::SHUTDOWN_CC ||
reason == JS::gcreason::DEBUG_MODE_GC ||
gckind == GC_SHRINK;
}

View File

@ -2204,19 +2204,29 @@ JS_FRIEND_API(unsigned)
js_GetScriptLineExtent(JSScript *script)
{
unsigned lineno = script->lineno;
unsigned maxLineNo = lineno;
unsigned maxLineNo = 0;
bool counting = true;
for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
if (type == SRC_SETLINE)
if (type == SRC_SETLINE) {
if (maxLineNo < lineno)
maxLineNo = lineno;
lineno = (unsigned) js_GetSrcNoteOffset(sn, 0);
else if (type == SRC_NEWLINE)
lineno++;
if (maxLineNo < lineno)
maxLineNo = lineno;
counting = true;
if (maxLineNo < lineno)
maxLineNo = lineno;
else
counting = false;
} else if (type == SRC_NEWLINE) {
if (counting)
lineno++;
}
}
return 1 + maxLineNo - script->lineno;
if (maxLineNo > lineno)
lineno = maxLineNo;
return 1 + lineno - script->lineno;
}
void
@ -2994,8 +3004,6 @@ LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
if (!res)
return nullptr;
cx->compartment()->scheduleDelazificationForDebugMode();
return new (res) LazyScript(fun, table, numFreeVariables, numInnerFunctions, version,
begin, end, lineno, column);
}

View File

@ -97,25 +97,6 @@ ReportMoreArgsNeeded(JSContext *cx, const char *name, unsigned required)
return false;
}
static inline bool
EnsureFunctionHasScript(JSContext *cx, JSFunction *fun)
{
if (fun->isInterpretedLazy()) {
AutoCompartment ac(cx, fun);
return !!fun->getOrCreateScript(cx);
}
return true;
}
static inline JSScript *
GetOrCreateFunctionScript(JSContext *cx, JSFunction *fun)
{
MOZ_ASSERT(fun->isInterpreted());
if (!EnsureFunctionHasScript(cx, fun))
return nullptr;
return fun->nonLazyScript();
}
#define REQUIRE_ARGC(name, n) \
JS_BEGIN_MACRO \
if (argc < (n)) \
@ -705,9 +686,6 @@ Debugger::wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp)
if (vp.isObject()) {
RootedObject obj(cx, &vp.toObject());
if (obj->is<JSFunction>() && !EnsureFunctionHasScript(cx, &obj->as<JSFunction>()))
return false;
ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj);
if (p) {
vp.setObject(*p->value);
@ -1145,8 +1123,6 @@ Debugger::slowPathOnNewScript(JSContext *cx, HandleScript script, GlobalObject *
JSTrapStatus
Debugger::onTrap(JSContext *cx, MutableHandleValue vp)
{
MOZ_ASSERT(cx->compartment()->debugMode());
ScriptFrameIter iter(cx);
RootedScript script(cx, iter.script());
Rooted<GlobalObject*> scriptGlobal(cx, &script->global());
@ -1973,20 +1949,16 @@ bool
Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg);
for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
// Invalidate a zone at a time to avoid doing a zone-wide CellIter
// per compartment.
AutoDebugModeInvalidation invalidate(zone);
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
if (c == dbg->object->compartment() || c->options().invisibleToDebugger())
continue;
c->zone()->scheduledForDestruction = false;
GlobalObject *global = c->maybeGlobal();
if (global) {
Rooted<GlobalObject*> rg(cx, global);
if (!dbg->addDebuggeeGlobal(cx, rg, invalidate))
return false;
}
AutoDebugModeGC dmgc(cx->runtime());
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
if (c == dbg->object->compartment() || c->options().invisibleToDebugger())
continue;
c->zone()->scheduledForDestruction = false;
GlobalObject *global = c->maybeGlobal();
if (global) {
Rooted<GlobalObject*> rg(cx, global);
if (!dbg->addDebuggeeGlobal(cx, rg, dmgc))
return false;
}
}
@ -2012,9 +1984,9 @@ bool
Debugger::removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
AutoDebugModeGC dmgc(cx->runtime());
for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), e.front(), nullptr, &e);
dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), e.front(), dmgc, nullptr, &e);
args.rval().setUndefined();
return true;
}
@ -2145,14 +2117,14 @@ Debugger::construct(JSContext *cx, unsigned argc, Value *vp)
bool
Debugger::addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> global)
{
AutoDebugModeInvalidation invalidate(global->compartment());
return addDebuggeeGlobal(cx, global, invalidate);
AutoDebugModeGC dmgc(cx->runtime());
return addDebuggeeGlobal(cx, global, dmgc);
}
bool
Debugger::addDebuggeeGlobal(JSContext *cx,
Handle<GlobalObject*> global,
AutoDebugModeInvalidation &invalidate)
AutoDebugModeGC &dmgc)
{
if (debuggees.has(global))
return true;
@ -2218,7 +2190,7 @@ Debugger::addDebuggeeGlobal(JSContext *cx,
} else {
if (global->getDebuggers()->length() > 1)
return true;
if (debuggeeCompartment->addDebuggee(cx, global, invalidate))
if (debuggeeCompartment->addDebuggee(cx, global, dmgc))
return true;
/* Maintain consistency on error. */
@ -2235,13 +2207,13 @@ Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
GlobalObjectSet::Enum *compartmentEnum,
GlobalObjectSet::Enum *debugEnum)
{
AutoDebugModeInvalidation invalidate(global->compartment());
return removeDebuggeeGlobal(fop, global, invalidate, compartmentEnum, debugEnum);
AutoDebugModeGC dmgc(fop->runtime());
return removeDebuggeeGlobal(fop, global, dmgc, compartmentEnum, debugEnum);
}
void
Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
AutoDebugModeInvalidation &invalidate,
AutoDebugModeGC &dmgc,
GlobalObjectSet::Enum *compartmentEnum,
GlobalObjectSet::Enum *debugEnum)
{
@ -2297,7 +2269,7 @@ Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
* global cannot be rooted on the stack without a cx.
*/
if (v->empty())
global->compartment()->removeDebuggee(fop, global, invalidate, compartmentEnum);
global->compartment()->removeDebuggee(fop, global, dmgc, compartmentEnum);
}
/*
@ -2425,14 +2397,10 @@ class Debugger::ScriptQuery {
if (!prepareQuery())
return false;
JSCompartment *singletonComp = nullptr;
if (compartments.count() == 1)
singletonComp = compartments.all().front();
/* Search each compartment for debuggee scripts. */
vector = v;
oom = false;
IterateScripts(cx->runtime(), singletonComp, this, considerScript);
IterateScripts(cx->runtime(), nullptr, this, considerScript);
if (oom) {
js_ReportOutOfMemory(cx);
return false;
@ -2502,21 +2470,10 @@ class Debugger::ScriptQuery {
/* Indicates whether OOM has occurred while matching. */
bool oom;
bool addCompartment(JSCompartment *comp) {
{
// All scripts in the debuggee compartment must be visible, so
// delazify everything.
AutoCompartment ac(cx, comp);
if (!comp->ensureDelazifyScriptsForDebugMode(cx))
return false;
}
return compartments.put(comp);
}
/* Arrange for this ScriptQuery to match only scripts that run in |global|. */
bool matchSingleGlobal(GlobalObject *global) {
JS_ASSERT(compartments.count() == 0);
if (!addCompartment(global->compartment())) {
if (!compartments.put(global->compartment())) {
js_ReportOutOfMemory(cx);
return false;
}
@ -2531,7 +2488,7 @@ class Debugger::ScriptQuery {
JS_ASSERT(compartments.count() == 0);
/* Build our compartment set from the debugger's set of debuggee globals. */
for (GlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) {
if (!addCompartment(r.front()->compartment())) {
if (!compartments.put(r.front()->compartment())) {
js_ReportOutOfMemory(cx);
return false;
}
@ -2974,10 +2931,8 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp)
for (uint32_t i = script->innerObjectsStart(); i < objects->length; i++) {
obj = objects->vector[i];
if (obj->is<JSFunction>()) {
fun = &obj->as<JSFunction>();
funScript = GetOrCreateFunctionScript(cx, fun);
if (!funScript)
return false;
fun = static_cast<JSFunction *>(obj.get());
funScript = fun->nonLazyScript();
s = dbg->wrapScript(cx, funScript);
if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
return false;
@ -4698,9 +4653,14 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp)
result->ensureDenseInitializedLength(cx, 0, fun->nargs);
if (fun->isInterpreted()) {
RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
if (!script)
return false;
RootedScript script(cx);
{
AutoCompartment ac(cx, fun);
script = fun->getOrCreateScript(cx);
if (!script)
return false;
}
JS_ASSERT(fun->nargs == script->bindings.numArgs());
@ -4742,9 +4702,15 @@ DebuggerObject_getScript(JSContext *cx, unsigned argc, Value *vp)
return true;
}
RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
if (!script)
return false;
RootedScript script(cx);
{
AutoCompartment ac(cx, obj);
script = fun->getOrCreateScript(cx);
if (!script)
return false;
}
/* Only hand out debuggee scripts. */
if (!dbg->observesScript(script)) {

View File

@ -230,12 +230,12 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj);
bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj,
AutoDebugModeInvalidation &invalidate);
AutoDebugModeGC &dmgc);
void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
GlobalObjectSet::Enum *compartmentEnum,
GlobalObjectSet::Enum *debugEnum);
void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
AutoDebugModeInvalidation &invalidate,
AutoDebugModeGC &dmgc,
GlobalObjectSet::Enum *compartmentEnum,
GlobalObjectSet::Enum *debugEnum);

View File

@ -1412,55 +1412,52 @@ CASE(EnableInterruptsPseudoOpcode)
moreInterrupts = true;
}
if (cx->compartment()->debugMode()) {
JSInterruptHook hook = cx->runtime()->debugHooks.interruptHook;
if (hook || script->stepModeEnabled()) {
RootedValue rval(cx);
JSTrapStatus status = JSTRAP_CONTINUE;
if (hook)
status = hook(cx, script, REGS.pc, rval.address(),
cx->runtime()->debugHooks.interruptHookData);
if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
status = Debugger::onSingleStep(cx, &rval);
switch (status) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
REGS.fp()->setReturnValue(rval);
interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
goto error;
default:;
}
moreInterrupts = true;
JSInterruptHook hook = cx->runtime()->debugHooks.interruptHook;
if (hook || script->stepModeEnabled()) {
RootedValue rval(cx);
JSTrapStatus status = JSTRAP_CONTINUE;
if (hook)
status = hook(cx, script, REGS.pc, rval.address(), cx->runtime()->debugHooks.interruptHookData);
if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
status = Debugger::onSingleStep(cx, &rval);
switch (status) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
REGS.fp()->setReturnValue(rval);
interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
goto error;
default:;
}
moreInterrupts = true;
}
if (script->hasAnyBreakpointsOrStepMode())
moreInterrupts = true;
if (script->hasAnyBreakpointsOrStepMode())
moreInterrupts = true;
if (script->hasBreakpointsAt(REGS.pc)) {
RootedValue rval(cx);
JSTrapStatus status = Debugger::onTrap(cx, &rval);
switch (status) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_RETURN:
REGS.fp()->setReturnValue(rval);
interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
goto error;
default:
break;
}
JS_ASSERT(status == JSTRAP_CONTINUE);
JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
if (script->hasBreakpointsAt(REGS.pc)) {
RootedValue rval(cx);
JSTrapStatus status = Debugger::onTrap(cx, &rval);
switch (status) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_RETURN:
REGS.fp()->setReturnValue(rval);
interpReturnOK = true;
goto forced_return;
case JSTRAP_THROW:
cx->setPendingException(rval);
goto error;
default:
break;
}
JS_ASSERT(status == JSTRAP_CONTINUE);
JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
}
JS_ASSERT(activation.opMask() == EnableInterruptsPseudoOpcode);

View File

@ -170,16 +170,13 @@ js::DebugExceptionUnwind(JSContext *cx, AbstractFramePtr frame, jsbytecode *pc)
JS_FRIEND_API(bool)
JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug)
{
for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
// Invalidate a zone at a time to avoid doing a zone-wide CellIter
// per compartment.
AutoDebugModeInvalidation invalidate(zone);
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
// Ignore special compartments (atoms, JSD compartments)
if (c->principals) {
if (!c->setDebugModeFromC(cx, !!debug, invalidate))
return false;
}
AutoDebugModeGC dmgc(cx->runtime());
for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
// Ignore special compartments (atoms, JSD compartments)
if (c->principals) {
if (!c->setDebugModeFromC(cx, !!debug, dmgc))
return false;
}
}
return true;
@ -188,8 +185,8 @@ JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug)
JS_FRIEND_API(bool)
JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, bool debug)
{
AutoDebugModeInvalidation invalidate(comp);
return comp->setDebugModeFromC(cx, !!debug, invalidate);
AutoDebugModeGC dmgc(cx->runtime());
return comp->setDebugModeFromC(cx, !!debug, dmgc);
}
static bool