mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 716647 - Part 5: Relax the no on-stack scripts restriction for addDebuggee. (r=jimb)
This commit is contained in:
parent
6e13279fe5
commit
e31d8af3d3
@ -12,7 +12,9 @@
|
|||||||
#include "jit/IonSpewer.h"
|
#include "jit/IonSpewer.h"
|
||||||
#include "jit/Recover.h"
|
#include "jit/Recover.h"
|
||||||
#include "jit/RematerializedFrame.h"
|
#include "jit/RematerializedFrame.h"
|
||||||
|
|
||||||
#include "vm/ArgumentsObject.h"
|
#include "vm/ArgumentsObject.h"
|
||||||
|
#include "vm/Debugger.h"
|
||||||
#include "vm/TraceLogging.h"
|
#include "vm/TraceLogging.h"
|
||||||
|
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
@ -1536,7 +1538,7 @@ HandleBaselineInfoBailout(JSContext *cx, JSScript *outerScript, JSScript *innerS
|
|||||||
return Invalidate(cx, outerScript);
|
return Invalidate(cx, outerScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
CopyFromRematerializedFrame(JSContext *cx, JitActivation *act, uint8_t *fp, size_t inlineDepth,
|
CopyFromRematerializedFrame(JSContext *cx, JitActivation *act, uint8_t *fp, size_t inlineDepth,
|
||||||
BaselineFrame *frame)
|
BaselineFrame *frame)
|
||||||
{
|
{
|
||||||
@ -1545,7 +1547,7 @@ CopyFromRematerializedFrame(JSContext *cx, JitActivation *act, uint8_t *fp, size
|
|||||||
// We might not have rematerialized a frame if the user never requested a
|
// We might not have rematerialized a frame if the user never requested a
|
||||||
// Debugger.Frame for it.
|
// Debugger.Frame for it.
|
||||||
if (!rematFrame)
|
if (!rematFrame)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
MOZ_ASSERT(rematFrame->script() == frame->script());
|
MOZ_ASSERT(rematFrame->script() == frame->script());
|
||||||
MOZ_ASSERT(rematFrame->numActualArgs() == frame->numActualArgs());
|
MOZ_ASSERT(rematFrame->numActualArgs() == frame->numActualArgs());
|
||||||
@ -1562,6 +1564,11 @@ CopyFromRematerializedFrame(JSContext *cx, JitActivation *act, uint8_t *fp, size
|
|||||||
IonSpew(IonSpew_BaselineBailouts,
|
IonSpew(IonSpew_BaselineBailouts,
|
||||||
" Copied from rematerialized frame at (%p,%u)",
|
" Copied from rematerialized frame at (%p,%u)",
|
||||||
fp, inlineDepth);
|
fp, inlineDepth);
|
||||||
|
|
||||||
|
if (cx->compartment()->debugMode())
|
||||||
|
return Debugger::handleIonBailout(cx, rematFrame, frame);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
@ -1661,9 +1668,11 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
|
|||||||
JitFrameIterator iter(cx);
|
JitFrameIterator iter(cx);
|
||||||
size_t inlineDepth = numFrames;
|
size_t inlineDepth = numFrames;
|
||||||
while (inlineDepth > 0) {
|
while (inlineDepth > 0) {
|
||||||
if (iter.isBaselineJS()) {
|
if (iter.isBaselineJS() &&
|
||||||
inlineDepth--;
|
!CopyFromRematerializedFrame(cx, act, outerFp, --inlineDepth,
|
||||||
CopyFromRematerializedFrame(cx, act, outerFp, inlineDepth, iter.baselineFrame());
|
iter.baselineFrame()))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
|
@ -3036,6 +3036,28 @@ jit::RematerializeAllFrames(JSContext *cx, JSCompartment *comp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
jit::UpdateForDebugMode(JSContext *maybecx, JSCompartment *comp,
|
||||||
|
AutoDebugModeInvalidation &invalidate)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(invalidate.isFor(comp));
|
||||||
|
|
||||||
|
// Schedule invalidation of all optimized JIT code since debug mode
|
||||||
|
// invalidates assumptions.
|
||||||
|
invalidate.scheduleInvalidation(comp->debugMode());
|
||||||
|
|
||||||
|
// Recompile on-stack baseline scripts if we have a cx.
|
||||||
|
if (maybecx) {
|
||||||
|
IonContext ictx(maybecx, nullptr);
|
||||||
|
if (!RecompileOnStackBaselineScriptsForDebugMode(maybecx, comp)) {
|
||||||
|
js_ReportOutOfMemory(maybecx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
AutoDebugModeInvalidation::~AutoDebugModeInvalidation()
|
AutoDebugModeInvalidation::~AutoDebugModeInvalidation()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!!comp_ != !!zone_);
|
MOZ_ASSERT(!!comp_ != !!zone_);
|
||||||
@ -3054,11 +3076,13 @@ AutoDebugModeInvalidation::~AutoDebugModeInvalidation()
|
|||||||
StopAllOffThreadCompilations(comp);
|
StopAllOffThreadCompilations(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't discard active baseline scripts. They are recompiled for debug
|
||||||
|
// mode.
|
||||||
jit::MarkActiveBaselineScripts(zone);
|
jit::MarkActiveBaselineScripts(zone);
|
||||||
|
|
||||||
for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
|
for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
|
||||||
JSCompartment *comp = iter.activation()->compartment();
|
JSCompartment *comp = iter.activation()->compartment();
|
||||||
if ((comp_ && comp_ == comp) || (zone_ && zone_ == comp->zone())) {
|
if (comp_ == comp || zone_ == comp->zone()) {
|
||||||
IonContext ictx(CompileRuntime::get(rt));
|
IonContext ictx(CompileRuntime::get(rt));
|
||||||
AutoFlushCache afc("AutoDebugModeInvalidation", rt->jitRuntime());
|
AutoFlushCache afc("AutoDebugModeInvalidation", rt->jitRuntime());
|
||||||
IonSpew(IonSpew_Invalidate, "Invalidating frames for debug mode toggle");
|
IonSpew(IonSpew_Invalidate, "Invalidating frames for debug mode toggle");
|
||||||
@ -3068,7 +3092,7 @@ AutoDebugModeInvalidation::~AutoDebugModeInvalidation()
|
|||||||
|
|
||||||
for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||||
JSScript *script = i.get<JSScript>();
|
JSScript *script = i.get<JSScript>();
|
||||||
if ((comp_ && script->compartment() == comp_) || zone_) {
|
if (script->compartment() == comp_ || zone_) {
|
||||||
FinishInvalidation<SequentialExecution>(fop, script);
|
FinishInvalidation<SequentialExecution>(fop, script);
|
||||||
FinishInvalidation<ParallelExecution>(fop, script);
|
FinishInvalidation<ParallelExecution>(fop, script);
|
||||||
FinishDiscardBaselineScript(fop, script);
|
FinishDiscardBaselineScript(fop, script);
|
||||||
|
@ -189,6 +189,8 @@ void TraceIonScripts(JSTracer* trc, JSScript *script);
|
|||||||
void RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode);
|
void RequestInterruptForIonCode(JSRuntime *rt, JSRuntime::InterruptMode mode);
|
||||||
|
|
||||||
bool RematerializeAllFrames(JSContext *cx, JSCompartment *comp);
|
bool RematerializeAllFrames(JSContext *cx, JSCompartment *comp);
|
||||||
|
bool UpdateForDebugMode(JSContext *maybecx, JSCompartment *comp,
|
||||||
|
AutoDebugModeInvalidation &invalidate);
|
||||||
|
|
||||||
} // namespace jit
|
} // namespace jit
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
@ -766,16 +766,13 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidatio
|
|||||||
bool enabledBefore = debugMode();
|
bool enabledBefore = debugMode();
|
||||||
bool enabledAfter = (debugModeBits & DebugModeFromMask & ~DebugFromC) || b;
|
bool enabledAfter = (debugModeBits & DebugModeFromMask & ~DebugFromC) || b;
|
||||||
|
|
||||||
// Debug mode can be enabled only when no scripts from the target
|
// Enabling debug mode from C (vs of from JS) can only be done when no
|
||||||
// compartment are on the stack. It would even be incorrect to discard just
|
// scripts from the target compartment are on the stack.
|
||||||
// the non-live scripts' JITScripts because they might share ICs with live
|
|
||||||
// scripts (bug 632343).
|
|
||||||
//
|
//
|
||||||
// We do allow disabling debug mode while scripts are on the stack. In
|
// We do allow disabling debug mode while scripts are on the stack. In
|
||||||
// that case the debug-mode code for those scripts remains, so subsequently
|
// that case the debug-mode code for those scripts remains, so subsequently
|
||||||
// hooks may be called erroneously, even though debug mode is supposedly
|
// hooks may be called erroneously, even though debug mode is supposedly
|
||||||
// off, and we have to live with it.
|
// off, and we have to live with it.
|
||||||
//
|
|
||||||
bool onStack = false;
|
bool onStack = false;
|
||||||
if (enabledBefore != enabledAfter) {
|
if (enabledBefore != enabledAfter) {
|
||||||
onStack = hasScriptsOnStack();
|
onStack = hasScriptsOnStack();
|
||||||
@ -788,36 +785,28 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidatio
|
|||||||
debugModeBits = (debugModeBits & ~DebugFromC) | (b ? DebugFromC : 0);
|
debugModeBits = (debugModeBits & ~DebugFromC) | (b ? DebugFromC : 0);
|
||||||
JS_ASSERT(debugMode() == enabledAfter);
|
JS_ASSERT(debugMode() == enabledAfter);
|
||||||
if (enabledBefore != enabledAfter) {
|
if (enabledBefore != enabledAfter) {
|
||||||
updateForDebugMode(cx->runtime()->defaultFreeOp(), invalidate);
|
// Pass in a nullptr cx to not bother recompiling for JSD1, since
|
||||||
|
// we're still enforcing the idle-stack invariant here.
|
||||||
|
if (!updateJITForDebugMode(nullptr, invalidate))
|
||||||
|
return false;
|
||||||
if (!enabledAfter)
|
if (!enabledAfter)
|
||||||
DebugScopes::onCompartmentLeaveDebugMode(this);
|
DebugScopes::onCompartmentLeaveDebugMode(this);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
JSCompartment::updateForDebugMode(FreeOp *fop, AutoDebugModeInvalidation &invalidate)
|
JSCompartment::updateJITForDebugMode(JSContext *maybecx, AutoDebugModeInvalidation &invalidate)
|
||||||
{
|
{
|
||||||
JSRuntime *rt = runtimeFromMainThread();
|
|
||||||
|
|
||||||
for (ContextIter acx(rt); !acx.done(); acx.next()) {
|
|
||||||
if (acx->compartment() == this)
|
|
||||||
acx->updateJITEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_ION
|
#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.
|
|
||||||
//
|
|
||||||
// The AutoDebugModeInvalidation argument makes sure we can't forget to
|
// The AutoDebugModeInvalidation argument makes sure we can't forget to
|
||||||
// invalidate, but it is also important not to run any scripts in this
|
// invalidate, but it is also important not to run any scripts in this
|
||||||
// compartment until the invalidate is destroyed. That is the caller's
|
// compartment until the invalidate is destroyed. That is the caller's
|
||||||
// responsibility.
|
// responsibility.
|
||||||
invalidate.scheduleInvalidation(debugMode());
|
if (!jit::UpdateForDebugMode(maybecx, this, invalidate))
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -840,25 +829,47 @@ JSCompartment::addDebuggee(JSContext *cx,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
debugModeBits |= DebugFromJS;
|
debugModeBits |= DebugFromJS;
|
||||||
if (!wasEnabled)
|
if (!wasEnabled && !updateJITForDebugMode(cx, invalidate))
|
||||||
updateForDebugMode(cx->runtime()->defaultFreeOp(), invalidate);
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
JSCompartment::removeDebuggee(FreeOp *fop,
|
JSCompartment::removeDebuggee(JSContext *cx,
|
||||||
js::GlobalObject *global,
|
js::GlobalObject *global,
|
||||||
js::GlobalObjectSet::Enum *debuggeesEnum)
|
js::GlobalObjectSet::Enum *debuggeesEnum)
|
||||||
{
|
{
|
||||||
AutoDebugModeInvalidation invalidate(this);
|
AutoDebugModeInvalidation invalidate(this);
|
||||||
return removeDebuggee(fop, global, invalidate, debuggeesEnum);
|
return removeDebuggee(cx, global, invalidate, debuggeesEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
JSCompartment::removeDebuggee(FreeOp *fop,
|
JSCompartment::removeDebuggee(JSContext *cx,
|
||||||
js::GlobalObject *global,
|
js::GlobalObject *global,
|
||||||
AutoDebugModeInvalidation &invalidate,
|
AutoDebugModeInvalidation &invalidate,
|
||||||
js::GlobalObjectSet::Enum *debuggeesEnum)
|
js::GlobalObjectSet::Enum *debuggeesEnum)
|
||||||
|
{
|
||||||
|
bool wasEnabled = debugMode();
|
||||||
|
removeDebuggeeUnderGC(cx->runtime()->defaultFreeOp(), global, invalidate, debuggeesEnum);
|
||||||
|
if (wasEnabled && !debugMode() && !updateJITForDebugMode(cx, invalidate))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
JSCompartment::removeDebuggeeUnderGC(FreeOp *fop,
|
||||||
|
js::GlobalObject *global,
|
||||||
|
js::GlobalObjectSet::Enum *debuggeesEnum)
|
||||||
|
{
|
||||||
|
AutoDebugModeInvalidation invalidate(this);
|
||||||
|
removeDebuggeeUnderGC(fop, global, invalidate, debuggeesEnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
JSCompartment::removeDebuggeeUnderGC(FreeOp *fop,
|
||||||
|
js::GlobalObject *global,
|
||||||
|
AutoDebugModeInvalidation &invalidate,
|
||||||
|
js::GlobalObjectSet::Enum *debuggeesEnum)
|
||||||
{
|
{
|
||||||
bool wasEnabled = debugMode();
|
bool wasEnabled = debugMode();
|
||||||
JS_ASSERT(debuggees.has(global));
|
JS_ASSERT(debuggees.has(global));
|
||||||
@ -869,10 +880,8 @@ JSCompartment::removeDebuggee(FreeOp *fop,
|
|||||||
|
|
||||||
if (debuggees.empty()) {
|
if (debuggees.empty()) {
|
||||||
debugModeBits &= ~DebugFromJS;
|
debugModeBits &= ~DebugFromJS;
|
||||||
if (wasEnabled && !debugMode()) {
|
if (wasEnabled && !debugMode())
|
||||||
DebugScopes::onCompartmentLeaveDebugMode(this);
|
DebugScopes::onCompartmentLeaveDebugMode(this);
|
||||||
updateForDebugMode(fop, invalidate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,18 +395,23 @@ struct JSCompartment
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
/* This is called only when debugMode() has just toggled. */
|
/* This is called only when debugMode() has just toggled. */
|
||||||
void updateForDebugMode(js::FreeOp *fop, js::AutoDebugModeInvalidation &invalidate);
|
bool updateJITForDebugMode(JSContext *maybecx, js::AutoDebugModeInvalidation &invalidate);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
js::GlobalObjectSet &getDebuggees() { return debuggees; }
|
js::GlobalObjectSet &getDebuggees() { return debuggees; }
|
||||||
bool addDebuggee(JSContext *cx, js::GlobalObject *global);
|
bool addDebuggee(JSContext *cx, js::GlobalObject *global);
|
||||||
bool addDebuggee(JSContext *cx, js::GlobalObject *global,
|
bool addDebuggee(JSContext *cx, js::GlobalObject *global,
|
||||||
js::AutoDebugModeInvalidation &invalidate);
|
js::AutoDebugModeInvalidation &invalidate);
|
||||||
void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global,
|
bool removeDebuggee(JSContext *cx, js::GlobalObject *global,
|
||||||
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
|
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
|
||||||
void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global,
|
bool removeDebuggee(JSContext *cx, js::GlobalObject *global,
|
||||||
js::AutoDebugModeInvalidation &invalidate,
|
js::AutoDebugModeInvalidation &invalidate,
|
||||||
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
|
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
|
||||||
|
void removeDebuggeeUnderGC(js::FreeOp *fop, js::GlobalObject *global,
|
||||||
|
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
|
||||||
|
void removeDebuggeeUnderGC(js::FreeOp *fop, js::GlobalObject *global,
|
||||||
|
js::AutoDebugModeInvalidation &invalidate,
|
||||||
|
js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
|
||||||
bool setDebugModeFromC(JSContext *cx, bool b,
|
bool setDebugModeFromC(JSContext *cx, bool b,
|
||||||
js::AutoDebugModeInvalidation &invalidate);
|
js::AutoDebugModeInvalidation &invalidate);
|
||||||
|
|
||||||
|
@ -1655,8 +1655,12 @@ Debugger::sweepAll(FreeOp *fop)
|
|||||||
* might be GC'd too. Since detaching requires access to both
|
* might be GC'd too. Since detaching requires access to both
|
||||||
* objects, this must be done before finalize time.
|
* objects, this must be done before finalize time.
|
||||||
*/
|
*/
|
||||||
for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
|
for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront()) {
|
||||||
dbg->removeDebuggeeGlobal(fop, e.front(), nullptr, &e);
|
// We can't recompile on-stack scripts here, and we
|
||||||
|
// can only toggle debug mode to off, so we use an
|
||||||
|
// infallible variant of removeDebuggeeGlobal.
|
||||||
|
dbg->removeDebuggeeGlobalUnderGC(fop, e.front(), nullptr, &e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1665,8 +1669,10 @@ Debugger::sweepAll(FreeOp *fop)
|
|||||||
GlobalObjectSet &debuggees = comp->getDebuggees();
|
GlobalObjectSet &debuggees = comp->getDebuggees();
|
||||||
for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
|
for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
|
||||||
GlobalObject *global = e.front();
|
GlobalObject *global = e.front();
|
||||||
if (IsObjectAboutToBeFinalized(&global))
|
if (IsObjectAboutToBeFinalized(&global)) {
|
||||||
|
// See infallibility note above.
|
||||||
detachAllDebuggersFromGlobal(fop, global, &e);
|
detachAllDebuggersFromGlobal(fop, global, &e);
|
||||||
|
}
|
||||||
else if (global != e.front())
|
else if (global != e.front())
|
||||||
e.rekeyFront(global);
|
e.rekeyFront(global);
|
||||||
}
|
}
|
||||||
@ -1680,7 +1686,7 @@ Debugger::detachAllDebuggersFromGlobal(FreeOp *fop, GlobalObject *global,
|
|||||||
const GlobalObject::DebuggerVector *debuggers = global->getDebuggers();
|
const GlobalObject::DebuggerVector *debuggers = global->getDebuggers();
|
||||||
JS_ASSERT(!debuggers->empty());
|
JS_ASSERT(!debuggers->empty());
|
||||||
while (!debuggers->empty())
|
while (!debuggers->empty())
|
||||||
debuggers->back()->removeDebuggeeGlobal(fop, global, compartmentEnum, nullptr);
|
debuggers->back()->removeDebuggeeGlobalUnderGC(fop, global, compartmentEnum, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
@ -2018,6 +2024,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
// Invalidate a zone at a time to avoid doing a zone-wide CellIter
|
// Invalidate a zone at a time to avoid doing a zone-wide CellIter
|
||||||
// per compartment.
|
// per compartment.
|
||||||
AutoDebugModeInvalidation invalidate(zone);
|
AutoDebugModeInvalidation invalidate(zone);
|
||||||
|
|
||||||
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
||||||
if (c == dbg->object->compartment() || c->options().invisibleToDebugger())
|
if (c == dbg->object->compartment() || c->options().invisibleToDebugger())
|
||||||
continue;
|
continue;
|
||||||
@ -2043,8 +2050,10 @@ Debugger::removeDebuggee(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
GlobalObject *global = dbg->unwrapDebuggeeArgument(cx, args[0]);
|
GlobalObject *global = dbg->unwrapDebuggeeArgument(cx, args[0]);
|
||||||
if (!global)
|
if (!global)
|
||||||
return false;
|
return false;
|
||||||
if (dbg->debuggees.has(global))
|
if (dbg->debuggees.has(global)) {
|
||||||
dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), global, nullptr, nullptr);
|
if (!dbg->removeDebuggeeGlobal(cx, global, nullptr, nullptr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2053,8 +2062,11 @@ bool
|
|||||||
Debugger::removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp)
|
Debugger::removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp)
|
||||||
{
|
{
|
||||||
THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
|
THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
|
||||||
for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
|
|
||||||
dbg->removeDebuggeeGlobal(cx->runtime()->defaultFreeOp(), e.front(), nullptr, &e);
|
for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront()) {
|
||||||
|
if (!dbg->removeDebuggeeGlobal(cx, e.front(), nullptr, &e))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
args.rval().setUndefined();
|
args.rval().setUndefined();
|
||||||
return true;
|
return true;
|
||||||
@ -2098,15 +2110,14 @@ Debugger::getNewestFrame(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
|
|
||||||
/* Since there may be multiple contexts, use AllFramesIter. */
|
/* Since there may be multiple contexts, use AllFramesIter. */
|
||||||
for (AllFramesIter i(cx); !i.done(); ++i) {
|
for (AllFramesIter i(cx); !i.done(); ++i) {
|
||||||
/*
|
if (dbg->observesFrame(i)) {
|
||||||
* Debug-mode currently disables Ion compilation in the compartment of
|
// Ensure that Ion frames are rematerialized. Only rematerialized
|
||||||
* the debuggee.
|
// Ion frames may be used as AbstractFramePtrs.
|
||||||
*/
|
if (i.isIon() && !i.ensureHasRematerializedFrame())
|
||||||
if (i.isIon())
|
return false;
|
||||||
continue;
|
AbstractFramePtr frame = i.abstractFramePtr();
|
||||||
if (dbg->observesFrame(i.abstractFramePtr())) {
|
|
||||||
ScriptFrameIter iter(i.activation()->cx(), ScriptFrameIter::GO_THROUGH_SAVED);
|
ScriptFrameIter iter(i.activation()->cx(), ScriptFrameIter::GO_THROUGH_SAVED);
|
||||||
while (iter.isIon() || iter.abstractFramePtr() != i.abstractFramePtr())
|
while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != frame)
|
||||||
++iter;
|
++iter;
|
||||||
return dbg->getScriptFrame(cx, iter, args.rval());
|
return dbg->getScriptFrame(cx, iter, args.rval());
|
||||||
}
|
}
|
||||||
@ -2248,12 +2259,6 @@ Debugger::addDebuggeeGlobal(JSContext *cx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Refuse to enable debug mode for a compartment that has running scripts. */
|
|
||||||
if (!debuggeeCompartment->debugMode() && debuggeeCompartment->hasScriptsOnStack()) {
|
|
||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each debugger-debuggee relation must be stored in up to three places.
|
* Each debugger-debuggee relation must be stored in up to three places.
|
||||||
* JSCompartment::addDebuggee enables debug mode if needed.
|
* JSCompartment::addDebuggee enables debug mode if needed.
|
||||||
@ -2281,19 +2286,10 @@ Debugger::addDebuggeeGlobal(JSContext *cx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
|
Debugger::cleanupDebuggeeGlobalBeforeRemoval(FreeOp *fop, GlobalObject *global,
|
||||||
GlobalObjectSet::Enum *compartmentEnum,
|
AutoDebugModeInvalidation &invalidate,
|
||||||
GlobalObjectSet::Enum *debugEnum)
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
{
|
GlobalObjectSet::Enum *debugEnum)
|
||||||
AutoDebugModeInvalidation invalidate(global->compartment());
|
|
||||||
removeDebuggeeGlobal(fop, global, invalidate, compartmentEnum, debugEnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
|
|
||||||
AutoDebugModeInvalidation &invalidate,
|
|
||||||
GlobalObjectSet::Enum *compartmentEnum,
|
|
||||||
GlobalObjectSet::Enum *debugEnum)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Each debuggee is in two HashSets: one for its compartment and one for
|
* Each debuggee is in two HashSets: one for its compartment and one for
|
||||||
@ -2351,14 +2347,57 @@ Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
|
|||||||
bp->destroy(fop);
|
bp->destroy(fop);
|
||||||
}
|
}
|
||||||
JS_ASSERT_IF(debuggees.empty(), !firstBreakpoint());
|
JS_ASSERT_IF(debuggees.empty(), !firstBreakpoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Debugger::removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnum)
|
||||||
|
{
|
||||||
|
AutoDebugModeInvalidation invalidate(global->compartment());
|
||||||
|
return removeDebuggeeGlobal(cx, global, invalidate, compartmentEnum, debugEnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Debugger::removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
|
||||||
|
AutoDebugModeInvalidation &invalidate,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnum)
|
||||||
|
{
|
||||||
|
cleanupDebuggeeGlobalBeforeRemoval(cx->runtime()->defaultFreeOp(), global,
|
||||||
|
invalidate, compartmentEnum, debugEnum);
|
||||||
|
|
||||||
|
// The debuggee needs to be removed from the compartment last to save a root.
|
||||||
|
if (global->getDebuggers()->empty())
|
||||||
|
return global->compartment()->removeDebuggee(cx, global, invalidate, compartmentEnum);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Debugger::removeDebuggeeGlobalUnderGC(FreeOp *fop, GlobalObject *global,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnum)
|
||||||
|
{
|
||||||
|
AutoDebugModeInvalidation invalidate(global->compartment());
|
||||||
|
removeDebuggeeGlobalUnderGC(fop, global, invalidate, compartmentEnum, debugEnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Debugger::removeDebuggeeGlobalUnderGC(FreeOp *fop, GlobalObject *global,
|
||||||
|
AutoDebugModeInvalidation &invalidate,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnum)
|
||||||
|
{
|
||||||
|
cleanupDebuggeeGlobalBeforeRemoval(fop, global, invalidate, compartmentEnum, debugEnum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The debuggee needs to be removed from the compartment last, as this can
|
* The debuggee needs to be removed from the compartment last, as this can
|
||||||
* trigger GCs if the compartment's debug mode is being changed, and the
|
* trigger GCs if the compartment's debug mode is being changed, and the
|
||||||
* global cannot be rooted on the stack without a cx.
|
* global cannot be rooted on the stack without a cx.
|
||||||
*/
|
*/
|
||||||
if (v->empty())
|
if (global->getDebuggers()->empty())
|
||||||
global->compartment()->removeDebuggee(fop, global, invalidate, compartmentEnum);
|
global->compartment()->removeDebuggeeUnderGC(fop, global, invalidate, compartmentEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3560,6 +3599,12 @@ Debugger::observesFrame(AbstractFramePtr frame) const
|
|||||||
return observesScript(frame.script());
|
return observesScript(frame.script());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Debugger::observesFrame(const ScriptFrameIter &iter) const
|
||||||
|
{
|
||||||
|
return observesScript(iter.script());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Debugger::observesScript(JSScript *script) const
|
Debugger::observesScript(JSScript *script) const
|
||||||
{
|
{
|
||||||
@ -3570,12 +3615,10 @@ Debugger::observesScript(JSScript *script) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
Debugger::handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to)
|
Debugger::replaceFrameGuts(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to,
|
||||||
|
ScriptFrameIter &iter)
|
||||||
{
|
{
|
||||||
ScriptFrameIter iter(cx);
|
for (Debugger::FrameRange r(from); !r.empty(); r.popFront()) {
|
||||||
JS_ASSERT(iter.abstractFramePtr() == to);
|
|
||||||
|
|
||||||
for (FrameRange r(from); !r.empty(); r.popFront()) {
|
|
||||||
RootedObject frameobj(cx, r.frontFrame());
|
RootedObject frameobj(cx, r.frontFrame());
|
||||||
Debugger *dbg = r.frontDebugger();
|
Debugger *dbg = r.frontDebugger();
|
||||||
JS_ASSERT(dbg == Debugger::fromChildJSObject(frameobj));
|
JS_ASSERT(dbg == Debugger::fromChildJSObject(frameobj));
|
||||||
@ -3600,6 +3643,31 @@ Debugger::handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::Baseline
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
Debugger::handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to)
|
||||||
|
{
|
||||||
|
ScriptFrameIter iter(cx);
|
||||||
|
JS_ASSERT(iter.abstractFramePtr() == to);
|
||||||
|
return replaceFrameGuts(cx, from, to, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
Debugger::handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::BaselineFrame *to)
|
||||||
|
{
|
||||||
|
// When we return to a bailed-out Ion real frame, we must update all
|
||||||
|
// Debugger.Frames that refer to its inline frames. However, since we
|
||||||
|
// can't pop individual inline frames off the stack (we can only pop the
|
||||||
|
// real frame that contains them all, as a unit), we cannot assume that
|
||||||
|
// the frame we're dealing with is the top frame. Advance the iterator
|
||||||
|
// across any inlined frames younger than |to|, the baseline frame
|
||||||
|
// reconstructed during bailout from the Ion frame corresponding to
|
||||||
|
// |from|.
|
||||||
|
ScriptFrameIter iter(cx);
|
||||||
|
while (iter.abstractFramePtr() != to)
|
||||||
|
++iter;
|
||||||
|
return replaceFrameGuts(cx, from, to, iter);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp)
|
DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp)
|
||||||
{
|
{
|
||||||
@ -4033,6 +4101,43 @@ static const JSFunctionSpec DebuggerSource_methods[] = {
|
|||||||
|
|
||||||
/*** Debugger.Frame ******************************************************************************/
|
/*** Debugger.Frame ******************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
UpdateFrameIterPc(FrameIter &iter)
|
||||||
|
{
|
||||||
|
if (iter.abstractFramePtr().isRematerializedFrame()) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Rematerialized frames don't need their pc updated. The reason we
|
||||||
|
// need to update pc is because we might get the same Debugger.Frame
|
||||||
|
// object for multiple re-entries into debugger code from debuggee
|
||||||
|
// code. This reentrancy is not possible with rematerialized frames,
|
||||||
|
// because when returning to debuggee code, we would have bailed out
|
||||||
|
// to baseline.
|
||||||
|
//
|
||||||
|
// We walk the stack to assert that it doesn't need updating.
|
||||||
|
jit::RematerializedFrame *frame = iter.abstractFramePtr().asRematerializedFrame();
|
||||||
|
jit::IonJSFrameLayout *jsFrame = (jit::IonJSFrameLayout *)frame->top();
|
||||||
|
jit::JitActivation *activation = iter.activation()->asJit();
|
||||||
|
|
||||||
|
ActivationIterator activationIter(activation->cx()->runtime());
|
||||||
|
while (activationIter.activation() != activation)
|
||||||
|
++activationIter;
|
||||||
|
|
||||||
|
jit::JitFrameIterator jitIter(activationIter);
|
||||||
|
while (!jitIter.isIonJS() || jitIter.jsFrame() != jsFrame)
|
||||||
|
++jitIter;
|
||||||
|
|
||||||
|
jit::InlineFrameIterator ionInlineIter(activation->cx(), &jitIter);
|
||||||
|
while (ionInlineIter.frameNo() != frame->frameNo())
|
||||||
|
++ionInlineIter;
|
||||||
|
|
||||||
|
MOZ_ASSERT(ionInlineIter.pc() == iter.pc());
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter.updatePcQuadratic();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DebuggerFrame_freeScriptFrameIterData(FreeOp *fop, JSObject *obj)
|
DebuggerFrame_freeScriptFrameIterData(FreeOp *fop, JSObject *obj)
|
||||||
{
|
{
|
||||||
@ -4175,6 +4280,27 @@ DebuggerFrame_getType(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DebuggerFrame_getImplementation(JSContext *cx, unsigned argc, Value *vp)
|
||||||
|
{
|
||||||
|
THIS_FRAME(cx, argc, vp, "get implementation", args, thisobj, frame);
|
||||||
|
|
||||||
|
const char *s;
|
||||||
|
if (frame.isBaselineFrame())
|
||||||
|
s = "baseline";
|
||||||
|
else if (frame.isRematerializedFrame())
|
||||||
|
s = "ion";
|
||||||
|
else
|
||||||
|
s = "interpreter";
|
||||||
|
|
||||||
|
JSAtom *str = Atomize(cx, s, strlen(s));
|
||||||
|
if (!str)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
args.rval().setString(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
|
DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
|
||||||
{
|
{
|
||||||
@ -4183,7 +4309,7 @@ DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
Rooted<Env*> env(cx);
|
Rooted<Env*> env(cx);
|
||||||
{
|
{
|
||||||
AutoCompartment ac(cx, iter.abstractFramePtr().scopeChain());
|
AutoCompartment ac(cx, iter.abstractFramePtr().scopeChain());
|
||||||
iter.updatePcQuadratic();
|
UpdateFrameIterPc(iter);
|
||||||
env = GetDebugScopeForFrame(cx, iter.abstractFramePtr(), iter.pc());
|
env = GetDebugScopeForFrame(cx, iter.abstractFramePtr(), iter.pc());
|
||||||
if (!env)
|
if (!env)
|
||||||
return false;
|
return false;
|
||||||
@ -4243,10 +4369,11 @@ DebuggerFrame_getOlder(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
||||||
|
|
||||||
for (++iter; !iter.done(); ++iter) {
|
for (++iter; !iter.done(); ++iter) {
|
||||||
if (iter.isIon())
|
if (dbg->observesFrame(iter)) {
|
||||||
continue;
|
if (iter.isIon() && !iter.ensureHasRematerializedFrame())
|
||||||
if (dbg->observesFrame(iter.abstractFramePtr()))
|
return false;
|
||||||
return dbg->getScriptFrame(cx, iter, args.rval());
|
return dbg->getScriptFrame(cx, iter, args.rval());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
args.rval().setNull();
|
args.rval().setNull();
|
||||||
return true;
|
return true;
|
||||||
@ -4408,7 +4535,7 @@ DebuggerFrame_getOffset(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
{
|
{
|
||||||
THIS_FRAME_ITER(cx, argc, vp, "get offset", args, thisobj, _, iter);
|
THIS_FRAME_ITER(cx, argc, vp, "get offset", args, thisobj, _, iter);
|
||||||
JSScript *script = iter.script();
|
JSScript *script = iter.script();
|
||||||
iter.updatePcQuadratic();
|
UpdateFrameIterPc(iter);
|
||||||
jsbytecode *pc = iter.pc();
|
jsbytecode *pc = iter.pc();
|
||||||
size_t offset = script->pcToOffset(pc);
|
size_t offset = script->pcToOffset(pc);
|
||||||
args.rval().setNumber(double(offset));
|
args.rval().setNumber(double(offset));
|
||||||
@ -4683,7 +4810,7 @@ DebuggerFrame_eval(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
THIS_FRAME_ITER(cx, argc, vp, "eval", args, thisobj, _, iter);
|
THIS_FRAME_ITER(cx, argc, vp, "eval", args, thisobj, _, iter);
|
||||||
REQUIRE_ARGC("Debugger.Frame.prototype.eval", 1);
|
REQUIRE_ARGC("Debugger.Frame.prototype.eval", 1);
|
||||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
||||||
iter.updatePcQuadratic();
|
UpdateFrameIterPc(iter);
|
||||||
return DebuggerGenericEval(cx, "Debugger.Frame.prototype.eval",
|
return DebuggerGenericEval(cx, "Debugger.Frame.prototype.eval",
|
||||||
args[0], EvalWithDefaultBindings, JS::UndefinedHandleValue,
|
args[0], EvalWithDefaultBindings, JS::UndefinedHandleValue,
|
||||||
args.get(1), args.rval(), dbg, js::NullPtr(), &iter);
|
args.get(1), args.rval(), dbg, js::NullPtr(), &iter);
|
||||||
@ -4695,7 +4822,7 @@ DebuggerFrame_evalWithBindings(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
THIS_FRAME_ITER(cx, argc, vp, "evalWithBindings", args, thisobj, _, iter);
|
THIS_FRAME_ITER(cx, argc, vp, "evalWithBindings", args, thisobj, _, iter);
|
||||||
REQUIRE_ARGC("Debugger.Frame.prototype.evalWithBindings", 2);
|
REQUIRE_ARGC("Debugger.Frame.prototype.evalWithBindings", 2);
|
||||||
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
Debugger *dbg = Debugger::fromChildJSObject(thisobj);
|
||||||
iter.updatePcQuadratic();
|
UpdateFrameIterPc(iter);
|
||||||
return DebuggerGenericEval(cx, "Debugger.Frame.prototype.evalWithBindings",
|
return DebuggerGenericEval(cx, "Debugger.Frame.prototype.evalWithBindings",
|
||||||
args[0], EvalHasExtraBindings, args[1], args.get(2),
|
args[0], EvalHasExtraBindings, args[1], args.get(2),
|
||||||
args.rval(), dbg, js::NullPtr(), &iter);
|
args.rval(), dbg, js::NullPtr(), &iter);
|
||||||
@ -4721,6 +4848,7 @@ static const JSPropertySpec DebuggerFrame_properties[] = {
|
|||||||
JS_PSG("script", DebuggerFrame_getScript, 0),
|
JS_PSG("script", DebuggerFrame_getScript, 0),
|
||||||
JS_PSG("this", DebuggerFrame_getThis, 0),
|
JS_PSG("this", DebuggerFrame_getThis, 0),
|
||||||
JS_PSG("type", DebuggerFrame_getType, 0),
|
JS_PSG("type", DebuggerFrame_getType, 0),
|
||||||
|
JS_PSG("implementation", DebuggerFrame_getImplementation, 0),
|
||||||
JS_PSGS("onStep", DebuggerFrame_getOnStep, DebuggerFrame_setOnStep, 0),
|
JS_PSGS("onStep", DebuggerFrame_getOnStep, DebuggerFrame_setOnStep, 0),
|
||||||
JS_PSGS("onPop", DebuggerFrame_getOnPop, DebuggerFrame_setOnPop, 0),
|
JS_PSGS("onPop", DebuggerFrame_getOnPop, DebuggerFrame_setOnPop, 0),
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
|
@ -239,13 +239,24 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||||||
bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj);
|
bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj);
|
||||||
bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj,
|
bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj,
|
||||||
AutoDebugModeInvalidation &invalidate);
|
AutoDebugModeInvalidation &invalidate);
|
||||||
void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
|
void cleanupDebuggeeGlobalBeforeRemoval(FreeOp *fop, GlobalObject *global,
|
||||||
|
AutoDebugModeInvalidation &invalidate,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnu);
|
||||||
|
bool removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
|
||||||
GlobalObjectSet::Enum *compartmentEnum,
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
GlobalObjectSet::Enum *debugEnum);
|
GlobalObjectSet::Enum *debugEnum);
|
||||||
void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
|
bool removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
|
||||||
AutoDebugModeInvalidation &invalidate,
|
AutoDebugModeInvalidation &invalidate,
|
||||||
GlobalObjectSet::Enum *compartmentEnum,
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
GlobalObjectSet::Enum *debugEnum);
|
GlobalObjectSet::Enum *debugEnum);
|
||||||
|
void removeDebuggeeGlobalUnderGC(FreeOp *fop, GlobalObject *global,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnum);
|
||||||
|
void removeDebuggeeGlobalUnderGC(FreeOp *fop, GlobalObject *global,
|
||||||
|
AutoDebugModeInvalidation &invalidate,
|
||||||
|
GlobalObjectSet::Enum *compartmentEnum,
|
||||||
|
GlobalObjectSet::Enum *debugEnum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cope with an error or exception in a debugger hook.
|
* Cope with an error or exception in a debugger hook.
|
||||||
@ -382,6 +393,9 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||||||
|
|
||||||
static inline Debugger *fromOnNewGlobalObjectWatchersLink(JSCList *link);
|
static inline Debugger *fromOnNewGlobalObjectWatchersLink(JSCList *link);
|
||||||
|
|
||||||
|
static bool replaceFrameGuts(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to,
|
||||||
|
ScriptFrameIter &iter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Debugger(JSContext *cx, JSObject *dbg);
|
Debugger(JSContext *cx, JSObject *dbg);
|
||||||
~Debugger();
|
~Debugger();
|
||||||
@ -428,6 +442,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||||||
static JSTrapStatus onTrap(JSContext *cx, MutableHandleValue vp);
|
static JSTrapStatus onTrap(JSContext *cx, MutableHandleValue vp);
|
||||||
static JSTrapStatus onSingleStep(JSContext *cx, MutableHandleValue vp);
|
static JSTrapStatus onSingleStep(JSContext *cx, MutableHandleValue vp);
|
||||||
static bool handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to);
|
static bool handleBaselineOsr(JSContext *cx, InterpreterFrame *from, jit::BaselineFrame *to);
|
||||||
|
static bool handleIonBailout(JSContext *cx, jit::RematerializedFrame *from, jit::BaselineFrame *to);
|
||||||
|
|
||||||
/************************************* Functions for use by Debugger.cpp. */
|
/************************************* Functions for use by Debugger.cpp. */
|
||||||
|
|
||||||
@ -436,6 +451,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||||||
inline bool observesNewGlobalObject() const;
|
inline bool observesNewGlobalObject() const;
|
||||||
inline bool observesGlobal(GlobalObject *global) const;
|
inline bool observesGlobal(GlobalObject *global) const;
|
||||||
bool observesFrame(AbstractFramePtr frame) const;
|
bool observesFrame(AbstractFramePtr frame) const;
|
||||||
|
bool observesFrame(const ScriptFrameIter &iter) const;
|
||||||
bool observesScript(JSScript *script) const;
|
bool observesScript(JSScript *script) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -762,7 +762,7 @@ GlobalObject::addDebugger(JSContext *cx, Handle<GlobalObject*> global, Debugger
|
|||||||
if (debuggers->empty() && !global->compartment()->addDebuggee(cx, global))
|
if (debuggers->empty() && !global->compartment()->addDebuggee(cx, global))
|
||||||
return false;
|
return false;
|
||||||
if (!debuggers->append(dbg)) {
|
if (!debuggers->append(dbg)) {
|
||||||
global->compartment()->removeDebuggee(cx->runtime()->defaultFreeOp(), global);
|
(void) global->compartment()->removeDebuggee(cx, global);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1059,9 +1059,44 @@ FrameIter::isConstructing() const
|
|||||||
MOZ_ASSUME_UNREACHABLE("Unexpected state");
|
MOZ_ASSUME_UNREACHABLE("Unexpected state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
FrameIter::ensureHasRematerializedFrame()
|
||||||
|
{
|
||||||
|
#ifdef JS_ION
|
||||||
|
MOZ_ASSERT(isIon());
|
||||||
|
return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
FrameIter::hasUsableAbstractFramePtr() const
|
||||||
|
{
|
||||||
|
switch (data_.state_) {
|
||||||
|
case DONE:
|
||||||
|
case ASMJS:
|
||||||
|
return false;
|
||||||
|
case JIT:
|
||||||
|
#ifdef JS_ION
|
||||||
|
if (data_.jitFrames_.isBaselineJS())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
MOZ_ASSERT(data_.jitFrames_.isIonJS());
|
||||||
|
return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
|
||||||
|
ionInlineFrames_.frameNo());
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case INTERP:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Unexpected state");
|
||||||
|
}
|
||||||
|
|
||||||
AbstractFramePtr
|
AbstractFramePtr
|
||||||
FrameIter::abstractFramePtr() const
|
FrameIter::abstractFramePtr() const
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(hasUsableAbstractFramePtr());
|
||||||
switch (data_.state_) {
|
switch (data_.state_) {
|
||||||
case DONE:
|
case DONE:
|
||||||
case ASMJS:
|
case ASMJS:
|
||||||
@ -1072,11 +1107,8 @@ FrameIter::abstractFramePtr() const
|
|||||||
return data_.jitFrames_.baselineFrame();
|
return data_.jitFrames_.baselineFrame();
|
||||||
|
|
||||||
MOZ_ASSERT(data_.jitFrames_.isIonJS());
|
MOZ_ASSERT(data_.jitFrames_.isIonJS());
|
||||||
jit::RematerializedFrame *frame =
|
return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
|
||||||
activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
|
ionInlineFrames_.frameNo());
|
||||||
ionInlineFrames_.frameNo());
|
|
||||||
MOZ_ASSERT(frame);
|
|
||||||
return frame;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1666,9 +1666,19 @@ class FrameIter
|
|||||||
size_t numFrameSlots() const;
|
size_t numFrameSlots() const;
|
||||||
Value frameSlotValue(size_t index) const;
|
Value frameSlotValue(size_t index) const;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// Ensures that we have rematerialized the top frame and its associated
|
||||||
// The following functions can only be called when isInterp() or isBaseline()
|
// inline frames. Can only be called when isIon().
|
||||||
// --------------------------------------------------------------------------
|
bool ensureHasRematerializedFrame();
|
||||||
|
|
||||||
|
// True when isInterp() or isBaseline(). True when isIon() if it
|
||||||
|
// has a rematerialized frame. False otherwise false otherwise.
|
||||||
|
bool hasUsableAbstractFramePtr() const;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------
|
||||||
|
// The following functions can only be called when isInterp(),
|
||||||
|
// isBaseline(), or isIon(). Further, abstractFramePtr() can
|
||||||
|
// only be called when hasUsableAbstractFramePtr().
|
||||||
|
// -----------------------------------------------------------
|
||||||
|
|
||||||
AbstractFramePtr abstractFramePtr() const;
|
AbstractFramePtr abstractFramePtr() const;
|
||||||
AbstractFramePtr copyDataAsAbstractFramePtr() const;
|
AbstractFramePtr copyDataAsAbstractFramePtr() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user