зеркало из https://github.com/mozilla/gecko-dev.git
bug 687966 - eliminating held/unheld scripts in the debugger. r=jorendorff
This commit is contained in:
Родитель
768ce0c081
Коммит
c162775c3e
|
@ -16,19 +16,11 @@ function ApplyToFrameScript(code, skip, f) {
|
|||
g.eval(code);
|
||||
}
|
||||
|
||||
var savedScript;
|
||||
|
||||
ApplyToFrameScript('debugger;', 0,
|
||||
function (script) {
|
||||
assertEq(script instanceof Debugger.Script, true);
|
||||
assertEq(script.live, true);
|
||||
savedScript = script;
|
||||
});
|
||||
assertEq(savedScript.live, false);
|
||||
ApplyToFrameScript("(function () { eval('debugger;'); })();", 0,
|
||||
function (script) {
|
||||
assertEq(script instanceof Debugger.Script, true);
|
||||
assertEq(script.live, true);
|
||||
savedScript = script;
|
||||
});
|
||||
assertEq(savedScript.live, false);
|
||||
|
|
|
@ -16,15 +16,10 @@ function ApplyToFrameScript(code, skip, f) {
|
|||
g.eval(code);
|
||||
}
|
||||
|
||||
var savedScript;
|
||||
|
||||
ApplyToFrameScript('(function () { debugger; })();', 0,
|
||||
function (script) {
|
||||
assertEq(script instanceof Debugger.Script, true);
|
||||
assertEq(script.live, true);
|
||||
savedScript = script;
|
||||
});
|
||||
assertEq(savedScript.live, true);
|
||||
|
||||
// This would be nice, once we can get host call frames:
|
||||
// ApplyToFrameScript("(function () { debugger; }).call(null);", 1,
|
||||
|
|
|
@ -10,5 +10,5 @@ assertEq(arr.length, 10);
|
|||
gc();
|
||||
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
assertEq(arr[i].live, true); // XXX FIXME - replace with something that touches the script
|
||||
assertEq(arr[i].lineCount, 1);
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ assertEq(arr.length, 100);
|
|||
gc(g);
|
||||
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
assertEq(arr[i].live, true); // XXX FIXME replace with something that touches the script
|
||||
assertEq(arr[i].lineCount, 1);
|
||||
|
||||
gc();
|
||||
|
|
|
@ -10,7 +10,6 @@ g.eval("function f() { return 2; }");
|
|||
var s;
|
||||
dbg.onDebuggerStatement = function (frame) { s = frame.eval("f").return.script; };
|
||||
g.eval("debugger;");
|
||||
assertEq(s.live, true);
|
||||
s.setBreakpoint(0, {}); // ok
|
||||
|
||||
dbg.removeDebuggee(gobj);
|
||||
|
|
|
@ -924,11 +924,8 @@ JSCompartment::markTrapClosuresIteratively(JSTracer *trc)
|
|||
for (BreakpointSiteMap::Range r = breakpointSites.all(); !r.empty(); r.popFront()) {
|
||||
BreakpointSite *site = r.front().value;
|
||||
|
||||
// Mark jsdbgapi state if any. But if we know the scriptObject, put off
|
||||
// marking trap state until we know the scriptObject is live.
|
||||
if (site->trapHandler &&
|
||||
(!site->scriptObject || !IsAboutToBeFinalized(cx, site->scriptObject)))
|
||||
{
|
||||
// Put off marking trap state until we know the script is live.
|
||||
if (site->trapHandler && !IsAboutToBeFinalized(cx, site->script)) {
|
||||
if (site->trapClosure.isMarkable() &&
|
||||
IsAboutToBeFinalized(cx, site->trapClosure.toGCThing()))
|
||||
{
|
||||
|
@ -945,21 +942,19 @@ JSCompartment::sweepBreakpoints(JSContext *cx)
|
|||
{
|
||||
for (BreakpointSiteMap::Enum e(breakpointSites); !e.empty(); e.popFront()) {
|
||||
BreakpointSite *site = e.front().value;
|
||||
if (site->scriptObject) {
|
||||
// clearTrap and nextbp are necessary here to avoid possibly
|
||||
// reading *site or *bp after destroying it.
|
||||
bool scriptGone = IsAboutToBeFinalized(cx, site->scriptObject);
|
||||
bool clearTrap = scriptGone && site->hasTrap();
|
||||
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
if (scriptGone || IsAboutToBeFinalized(cx, bp->debugger->toJSObject()))
|
||||
bp->destroy(cx, &e);
|
||||
}
|
||||
|
||||
if (clearTrap)
|
||||
site->clearTrap(cx, &e);
|
||||
// clearTrap and nextbp are necessary here to avoid possibly
|
||||
// reading *site or *bp after destroying it.
|
||||
bool scriptGone = IsAboutToBeFinalized(cx, site->script);
|
||||
bool clearTrap = scriptGone && site->hasTrap();
|
||||
|
||||
Breakpoint *nextbp;
|
||||
for (Breakpoint *bp = site->firstBreakpoint(); bp; bp = nextbp) {
|
||||
nextbp = bp->nextInSite();
|
||||
if (scriptGone || IsAboutToBeFinalized(cx, bp->debugger->toJSObject()))
|
||||
bp->destroy(cx, &e);
|
||||
}
|
||||
|
||||
if (clearTrap)
|
||||
site->clearTrap(cx, &e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2436,7 +2436,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
|||
return NULL;
|
||||
|
||||
js_CallNewScriptHook(cx, cfun->script(), cfun);
|
||||
Debugger::onNewScript(cx, cfun->script(), cfun, Debugger::NewHeldScript);
|
||||
Debugger::onNewScript(cx, cfun->script(), cfun, NULL);
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
|
|
|
@ -4936,14 +4936,6 @@ IsAboutToBeFinalized(JSContext *cx, TypeObjectKey *key)
|
|||
return !reinterpret_cast<const gc::Cell *>((jsuword) key & ~1)->isMarked();
|
||||
}
|
||||
|
||||
inline bool
|
||||
ScriptIsAboutToBeFinalized(JSContext *cx, JSScript *script, JSFunction *fun)
|
||||
{
|
||||
return script->isCachedEval ||
|
||||
(script->u.object && IsAboutToBeFinalized(cx, script->u.object)) ||
|
||||
(fun && IsAboutToBeFinalized(cx, fun));
|
||||
}
|
||||
|
||||
void
|
||||
TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
|
||||
{
|
||||
|
|
|
@ -1251,11 +1251,11 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||
/* Tell the debugger about this compiled script. */
|
||||
js_CallNewScriptHook(cx, script, fun);
|
||||
if (!cg->parent) {
|
||||
Debugger::onNewScript(cx, script,
|
||||
fun ? fun : (script->u.object ? script->u.object : cg->scopeChain()),
|
||||
(fun || script->u.object)
|
||||
? Debugger::NewHeldScript
|
||||
: Debugger::NewNonHeldScript);
|
||||
JSObject *owner = fun ? fun : script->u.object;
|
||||
GlobalObject *compileAndGoGlobal = NULL;
|
||||
if (script->compileAndGo)
|
||||
compileAndGoGlobal = (owner ? owner : cg->scopeChain())->getGlobal();
|
||||
Debugger::onNewScript(cx, script, owner, compileAndGoGlobal);
|
||||
}
|
||||
|
||||
return script;
|
||||
|
@ -1330,7 +1330,6 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
|
|||
if (JSDestroyScriptHook hook = cx->debugHooks->destroyScriptHook)
|
||||
hook(cx, script, cx->debugHooks->destroyScriptHookData);
|
||||
script->callDestroyHook = false;
|
||||
Debugger::onDestroyScript(script);
|
||||
JS_ClearScriptTraps(cx, script);
|
||||
}
|
||||
|
||||
|
|
|
@ -291,14 +291,14 @@ class DefaultMarkPolicy<JSObject *, Value> {
|
|||
};
|
||||
|
||||
template <>
|
||||
class DefaultMarkPolicy<JSObject *, JSObject *> {
|
||||
class DefaultMarkPolicy<gc::Cell *, JSObject *> {
|
||||
protected:
|
||||
JSTracer *tracer;
|
||||
public:
|
||||
DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
|
||||
bool keyMarked(JSObject *k) { return !IsAboutToBeFinalized(tracer->context, k); }
|
||||
bool keyMarked(gc::Cell *k) { return !IsAboutToBeFinalized(tracer->context, k); }
|
||||
bool valueMarked(JSObject *v) { return !IsAboutToBeFinalized(tracer->context, v); }
|
||||
bool markEntryIfLive(JSObject *k, JSObject *v) {
|
||||
bool markEntryIfLive(gc::Cell *k, JSObject *v) {
|
||||
if (keyMarked(k) && !valueMarked(v)) {
|
||||
js::gc::MarkObject(tracer, *v, "WeakMap entry value");
|
||||
return true;
|
||||
|
@ -317,7 +317,7 @@ class DefaultMarkPolicy<JSObject *, JSObject *> {
|
|||
// default mark policy. We give it a distinct name anyway, in case this ever
|
||||
// changes.
|
||||
//
|
||||
typedef DefaultMarkPolicy<JSObject *, JSObject *> CrossCompartmentMarkPolicy;
|
||||
typedef DefaultMarkPolicy<gc::Cell *, JSObject *> CrossCompartmentMarkPolicy;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -718,10 +718,11 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
|||
return false;
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
JS_ASSERT(!script->compileAndGo);
|
||||
if (!js_NewScriptObject(xdr->cx, script))
|
||||
return false;
|
||||
js_CallNewScriptHook(xdr->cx, script, NULL);
|
||||
Debugger::onNewScript(xdr->cx, script, script->u.object, Debugger::NewHeldScript);
|
||||
Debugger::onNewScript(xdr->cx, script, script->u.object, NULL);
|
||||
*scriptp = script;
|
||||
}
|
||||
|
||||
|
|
|
@ -312,7 +312,7 @@ Breakpoint::nextInSite()
|
|||
|
||||
Debugger::Debugger(JSContext *cx, JSObject *dbg)
|
||||
: object(dbg), uncaughtExceptionHook(NULL), enabled(true),
|
||||
frames(cx), objects(cx), heldScripts(cx), nonHeldScripts(cx)
|
||||
frames(cx), objects(cx), scripts(cx)
|
||||
{
|
||||
assertSameCompartment(cx, dbg);
|
||||
|
||||
|
@ -334,11 +334,10 @@ Debugger::~Debugger()
|
|||
bool
|
||||
Debugger::init(JSContext *cx)
|
||||
{
|
||||
bool ok = (frames.init() &&
|
||||
objects.init() &&
|
||||
debuggees.init() &&
|
||||
heldScripts.init() &&
|
||||
nonHeldScripts.init());
|
||||
bool ok = frames.init() &&
|
||||
objects.init() &&
|
||||
debuggees.init() &&
|
||||
scripts.init();
|
||||
if (!ok)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return ok;
|
||||
|
@ -405,13 +404,7 @@ Debugger::hasAnyLiveHooks(JSContext *cx) const
|
|||
|
||||
/* If any breakpoints are in live scripts, return true. */
|
||||
for (Breakpoint *bp = firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
|
||||
/*
|
||||
* If holder is non-null, examine it to see if the script will be
|
||||
* collected. If holder is null, then bp->site->script is an eval
|
||||
* script on the stack, so it is definitely live.
|
||||
*/
|
||||
JSObject *holder = bp->site->getScriptObject();
|
||||
if (!holder || !IsAboutToBeFinalized(cx, holder))
|
||||
if (!IsAboutToBeFinalized(cx, bp->site->script))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -494,7 +487,7 @@ Debugger::wrapDebuggeeValue(JSContext *cx, Value *vp)
|
|||
if (vp->isObject()) {
|
||||
JSObject *obj = &vp->toObject();
|
||||
|
||||
ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj);
|
||||
CellWeakMap::AddPtr p = objects.lookupForAdd(obj);
|
||||
if (p) {
|
||||
vp->setObject(*p->value);
|
||||
} else {
|
||||
|
@ -738,7 +731,7 @@ Debugger::fireEnterFrame(JSContext *cx)
|
|||
}
|
||||
|
||||
void
|
||||
Debugger::fireNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScriptKind kind)
|
||||
Debugger::fireNewScript(JSContext *cx, JSScript *script, JSObject *obj)
|
||||
{
|
||||
JSObject *hook = getHook(OnNewScript);
|
||||
JS_ASSERT(hook);
|
||||
|
@ -748,8 +741,7 @@ Debugger::fireNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScrip
|
|||
if (!ac.enter())
|
||||
return;
|
||||
|
||||
JSObject *dsobj =
|
||||
kind == NewHeldScript ? wrapHeldScript(cx, script, obj) : wrapNonHeldScript(cx, script);
|
||||
JSObject *dsobj = wrapScript(cx, script, obj);
|
||||
if (!dsobj) {
|
||||
handleUncaughtException(ac, NULL, false);
|
||||
return;
|
||||
|
@ -822,8 +814,11 @@ AddNewScriptRecipients(GlobalObject::DebuggerVector *src, AutoValueVector *dest)
|
|||
}
|
||||
|
||||
void
|
||||
Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScriptKind kind)
|
||||
Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj,
|
||||
GlobalObject *compileAndGoGlobal)
|
||||
{
|
||||
JS_ASSERT(script->compileAndGo == !!compileAndGoGlobal);
|
||||
|
||||
/*
|
||||
* Build the list of recipients. For compile-and-go scripts, this is the
|
||||
* same as the generic Debugger::dispatchHook code, but non-compile-and-go
|
||||
|
@ -831,15 +826,12 @@ Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, Ne
|
|||
* debugger observing any global in the script's compartment.
|
||||
*/
|
||||
AutoValueVector triggered(cx);
|
||||
GlobalObject *global;
|
||||
if (script->compileAndGo) {
|
||||
global = obj->getGlobal();
|
||||
if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
|
||||
if (GlobalObject::DebuggerVector *debuggers = compileAndGoGlobal->getDebuggers()) {
|
||||
if (!AddNewScriptRecipients(debuggers, &triggered))
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
global = NULL;
|
||||
GlobalObjectSet &debuggees = script->compartment()->getDebuggees();
|
||||
for (GlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
if (!AddNewScriptRecipients(r.front()->getDebuggers(), &triggered))
|
||||
|
@ -853,8 +845,10 @@ Debugger::slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj, Ne
|
|||
*/
|
||||
for (Value *p = triggered.begin(); p != triggered.end(); p++) {
|
||||
Debugger *dbg = Debugger::fromJSObject(&p->toObject());
|
||||
if ((!global || dbg->debuggees.has(global)) && dbg->enabled && dbg->getHook(OnNewScript))
|
||||
dbg->fireNewScript(cx, script, obj, kind);
|
||||
if ((!compileAndGoGlobal || dbg->debuggees.has(compileAndGoGlobal)) &&
|
||||
dbg->enabled && dbg->getHook(OnNewScript)) {
|
||||
dbg->fireNewScript(cx, script, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1011,7 +1005,7 @@ Debugger::onSingleStep(JSContext *cx, Value *vp)
|
|||
/*** Debugger JSObjects **************************************************************************/
|
||||
|
||||
void
|
||||
Debugger::markKeysInCompartment(JSTracer *tracer, const ObjectWeakMap &map)
|
||||
Debugger::markKeysInCompartment(JSTracer *tracer, const CellWeakMap &map, bool scripts)
|
||||
{
|
||||
JSCompartment *comp = tracer->context->runtime->gcCurrentCompartment;
|
||||
JS_ASSERT(comp);
|
||||
|
@ -1021,12 +1015,19 @@ Debugger::markKeysInCompartment(JSTracer *tracer, const ObjectWeakMap &map)
|
|||
* enumerating WeakMap keys. However in this case we need access, so we
|
||||
* make a base-class reference. Range is public in HashMap.
|
||||
*/
|
||||
typedef HashMap<JSObject *, JSObject *, DefaultHasher<JSObject *>, RuntimeAllocPolicy> Map;
|
||||
typedef HashMap<gc::Cell *, JSObject *, DefaultHasher<gc::Cell *>, RuntimeAllocPolicy> Map;
|
||||
const Map &storage = map;
|
||||
for (Map::Range r = storage.all(); !r.empty(); r.popFront()) {
|
||||
JSObject *key = r.front().key;
|
||||
if (key->compartment() == comp && IsAboutToBeFinalized(tracer->context, key))
|
||||
js::gc::MarkObject(tracer, *key, "cross-compartment WeakMap key");
|
||||
gc::Cell *key = r.front().key;
|
||||
if (key->compartment() == comp && IsAboutToBeFinalized(tracer->context, key)) {
|
||||
if (scripts) {
|
||||
js::gc::MarkScript(tracer, static_cast<JSScript *>(key),
|
||||
"cross-compartment WeakMap key");
|
||||
} else {
|
||||
js::gc::MarkObject(tracer, *static_cast<JSObject *>(key),
|
||||
"cross-compartment WeakMap key");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1042,7 +1043,7 @@ Debugger::markKeysInCompartment(JSTracer *tracer, const ObjectWeakMap &map)
|
|||
* manually.
|
||||
*
|
||||
* Each Debugger object keeps two cross-compartment WeakMaps: objects and
|
||||
* heldScripts. Both have the nice property that all their values are in the
|
||||
* scripts. Both have the nice property that all their values are in the
|
||||
* same compartment as the Debugger object, so we only need to mark the
|
||||
* keys. We must simply mark all keys that are in the compartment being GC'd.
|
||||
*
|
||||
|
@ -1066,8 +1067,8 @@ Debugger::markCrossCompartmentDebuggerObjectReferents(JSTracer *tracer)
|
|||
for (JSCList *p = &rt->debuggerList; (p = JS_NEXT_LINK(p)) != &rt->debuggerList;) {
|
||||
Debugger *dbg = Debugger::fromLinks(p);
|
||||
if (dbg->object->compartment() != comp) {
|
||||
markKeysInCompartment(tracer, dbg->objects);
|
||||
markKeysInCompartment(tracer, dbg->heldScripts);
|
||||
markKeysInCompartment(tracer, dbg->objects, false);
|
||||
markKeysInCompartment(tracer, dbg->scripts, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1145,8 +1146,7 @@ Debugger::markAllIteratively(GCMarker *trc)
|
|||
if (dbgMarked) {
|
||||
/* Search for breakpoints to mark. */
|
||||
for (Breakpoint *bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
|
||||
JSObject *scriptObject = bp->site->getScriptObject();
|
||||
if (!scriptObject || !IsAboutToBeFinalized(cx, scriptObject)) {
|
||||
if (!IsAboutToBeFinalized(cx, bp->site->script)) {
|
||||
/*
|
||||
* The debugger and the script are both live.
|
||||
* Therefore the breakpoint handler is live.
|
||||
|
@ -1195,23 +1195,8 @@ Debugger::trace(JSTracer *trc)
|
|||
/* Trace the referent -> Debugger.Object weak map. */
|
||||
objects.trace(trc);
|
||||
|
||||
/*
|
||||
* Trace the weak map from JSFunctions and "Script" JSObjects to
|
||||
* Debugger.Script objects.
|
||||
*/
|
||||
heldScripts.trace(trc);
|
||||
|
||||
/* Trace the map for non-held scripts, which are explicitly freed. */
|
||||
for (ScriptMap::Range r = nonHeldScripts.all(); !r.empty(); r.popFront()) {
|
||||
JSObject *scriptobj = r.front().value;
|
||||
|
||||
/*
|
||||
* nonHeldScripts should only refer to Debugger.Script objects for
|
||||
* scripts that haven't been freed yet.
|
||||
*/
|
||||
JS_ASSERT(scriptobj->getPrivate());
|
||||
MarkObject(trc, *scriptobj, "live eval Debugger.Script");
|
||||
}
|
||||
/* Trace the weak map from JSScript instances to Debugger.Script objects. */
|
||||
scripts.trace(trc);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1791,45 +1776,6 @@ JSFunctionSpec Debugger::methods[] = {
|
|||
|
||||
/*** Debugger.Script *****************************************************************************/
|
||||
|
||||
/*
|
||||
* JSScripts' lifetimes fall into to two categories:
|
||||
*
|
||||
* - "Held scripts": JSScripts belonging to JSFunctions and JSScripts created
|
||||
* using JSAPI have lifetimes determined by the garbage collector. A JSScript
|
||||
* itself has no mark bit of its own. Instead, its holding object manages the
|
||||
* JSScript as part of its own structure: the holder has a mark bit; when the
|
||||
* holder is marked it calls js_TraceScript on its JSScript; and when the
|
||||
* holder is freed it explicitly frees its JSScript.
|
||||
*
|
||||
* Debugger.Script instances for held scripts are strong references to the
|
||||
* holder (and thus to the script). Debugger::heldScripts weakly maps
|
||||
* debuggee holding objects to the Debugger.Script objects for their
|
||||
* JSScripts. We needn't act on a destroyScript event for a held script: if
|
||||
* we get such an event we know its Debugger.Script is dead anyway, and its
|
||||
* entry in Debugger::heldScripts will be cleaned up by the standard weak
|
||||
* table code.
|
||||
*
|
||||
* - "Non-held scripts": JSScripts generated temporarily for a call to eval or
|
||||
* JS_Evaluate*, live until the call completes, at which point the script is
|
||||
* destroyed.
|
||||
*
|
||||
* A Debugger.Script instance for a non-held script has no influence on the
|
||||
* JSScript's lifetime. Debugger::nonHeldScripts maps live JSScripts to to
|
||||
* their Debugger.Script objects. When a destroyScript event tells us that
|
||||
* a non-held script is dead, we remove its table entry, and clear its
|
||||
* Debugger.Script object's script pointer, thus marking it dead.
|
||||
*
|
||||
* A Debugger.Script's private pointer points directly to the JSScript, or is
|
||||
* NULL if the Debugger.Script is dead. The JSSLOT_DEBUGSCRIPT_HOLDER slot
|
||||
* refers to the holding object, or is null for non-held JSScripts. The private
|
||||
* pointer is not traced; the holding object reference, if present, is traced
|
||||
* via DebuggerScript_trace.
|
||||
*
|
||||
* (We consider a script saved in and retrieved from the eval cache to have
|
||||
* been destroyed, and then --- mirabile dictu --- re-created at the same
|
||||
* address. The newScriptHook and destroyScriptHook hooks cooperate with this
|
||||
* view.)
|
||||
*/
|
||||
static inline JSScript *
|
||||
GetScriptReferent(JSObject *obj)
|
||||
{
|
||||
|
@ -1837,13 +1783,6 @@ GetScriptReferent(JSObject *obj)
|
|||
return (JSScript *) obj->getPrivate();
|
||||
}
|
||||
|
||||
static inline void
|
||||
ClearScriptReferent(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->getClass() == &DebuggerScript_class);
|
||||
obj->setPrivate(NULL);
|
||||
}
|
||||
|
||||
static inline JSObject *
|
||||
GetScriptHolder(JSObject *obj)
|
||||
{
|
||||
|
@ -1856,6 +1795,8 @@ static void
|
|||
DebuggerScript_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
if (!trc->context->runtime->gcCurrentCompartment) {
|
||||
if (JSScript *script = GetScriptReferent(obj))
|
||||
MarkScript(trc, script, "Debugger.Script referent");
|
||||
Value v = obj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER);
|
||||
if (!v.isUndefined()) {
|
||||
if (JSObject *obj = (JSObject *) v.toPrivate())
|
||||
|
@ -1895,18 +1836,18 @@ Debugger::newDebuggerScript(JSContext *cx, JSScript *script, JSObject *holder)
|
|||
}
|
||||
|
||||
JSObject *
|
||||
Debugger::wrapHeldScript(JSContext *cx, JSScript *script, JSObject *obj)
|
||||
Debugger::wrapScript(JSContext *cx, JSScript *script, JSObject *obj)
|
||||
{
|
||||
assertSameCompartment(cx, object);
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
JS_ASSERT(script->compartment() == obj->compartment());
|
||||
JS_ASSERT_IF(obj, script->compartment() == obj->compartment());
|
||||
|
||||
ScriptWeakMap::AddPtr p = heldScripts.lookupForAdd(obj);
|
||||
CellWeakMap::AddPtr p = scripts.lookupForAdd(script);
|
||||
if (!p) {
|
||||
JSObject *scriptobj = newDebuggerScript(cx, script, obj);
|
||||
|
||||
/* The allocation may have caused a GC, which can remove table entries. */
|
||||
if (!scriptobj || !heldScripts.relookupOrAdd(p, obj, scriptobj))
|
||||
if (!scriptobj || !scripts.relookupOrAdd(p, script, scriptobj))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1917,61 +1858,11 @@ Debugger::wrapHeldScript(JSContext *cx, JSScript *script, JSObject *obj)
|
|||
JSObject *
|
||||
Debugger::wrapFunctionScript(JSContext *cx, JSFunction *fun)
|
||||
{
|
||||
return wrapHeldScript(cx, fun->script(), fun);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
Debugger::wrapJSAPIScript(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isScript());
|
||||
return wrapHeldScript(cx, obj->getScript(), obj);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
Debugger::wrapNonHeldScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
assertSameCompartment(cx, object);
|
||||
JS_ASSERT(cx->compartment != script->compartment());
|
||||
|
||||
ScriptMap::AddPtr p = nonHeldScripts.lookupForAdd(script);
|
||||
if (!p) {
|
||||
JSObject *scriptobj = newDebuggerScript(cx, script, NULL);
|
||||
|
||||
/* The allocation may have caused a GC, which can remove table entries. */
|
||||
if (!scriptobj || !nonHeldScripts.relookupOrAdd(p, script, scriptobj))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_ASSERT(GetScriptReferent(p->value) == script);
|
||||
return p->value;
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::slowPathOnDestroyScript(JSScript *script)
|
||||
{
|
||||
/* Find all debuggers that might have Debugger.Script referring to this script. */
|
||||
js::GlobalObjectSet *debuggees = &script->compartment()->getDebuggees();
|
||||
for (GlobalObjectSet::Range r = debuggees->all(); !r.empty(); r.popFront()) {
|
||||
GlobalObject::DebuggerVector *debuggers = r.front()->getDebuggers();
|
||||
for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++)
|
||||
(*p)->destroyNonHeldScript(script);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::destroyNonHeldScript(JSScript *script)
|
||||
{
|
||||
ScriptMap::Ptr p = nonHeldScripts.lookup(script);
|
||||
if (p) {
|
||||
JS_ASSERT(GetScriptReferent(p->value) == script);
|
||||
ClearScriptReferent(p->value);
|
||||
nonHeldScripts.remove(p);
|
||||
}
|
||||
return wrapScript(cx, fun->script(), fun);
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const char *fnname,
|
||||
bool checkLive)
|
||||
DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const char *fnname)
|
||||
{
|
||||
if (!v.isObject()) {
|
||||
ReportObjectRequired(cx);
|
||||
|
@ -1989,42 +1880,33 @@ DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const c
|
|||
* but whose holding object is undefined.
|
||||
*/
|
||||
if (thisobj->getReservedSlot(JSSLOT_DEBUGSCRIPT_HOLDER).isUndefined()) {
|
||||
JS_ASSERT(!GetScriptReferent(thisobj));
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
|
||||
clsname, fnname, "prototype object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (checkLive && !GetScriptReferent(thisobj)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_LIVE,
|
||||
clsname, fnname, "script");
|
||||
return NULL;
|
||||
}
|
||||
JS_ASSERT(GetScriptReferent(thisobj));
|
||||
|
||||
return thisobj;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
DebuggerScript_checkThis(JSContext *cx, const CallArgs &args, const char *fnname, bool checkLive)
|
||||
DebuggerScript_checkThis(JSContext *cx, const CallArgs &args, const char *fnname)
|
||||
{
|
||||
return DebuggerScript_check(cx, args.thisv(), "Debugger.Script", fnname, checkLive);
|
||||
return DebuggerScript_check(cx, args.thisv(), "Debugger.Script", fnname);
|
||||
}
|
||||
|
||||
#define THIS_DEBUGSCRIPT_SCRIPT_NEEDLIVE(cx, argc, vp, fnname, args, obj, script, checkLive) \
|
||||
#define THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, fnname, args, obj, script) \
|
||||
CallArgs args = CallArgsFromVp(argc, vp); \
|
||||
JSObject *obj = DebuggerScript_checkThis(cx, args, fnname, checkLive); \
|
||||
JSObject *obj = DebuggerScript_checkThis(cx, args, fnname); \
|
||||
if (!obj) \
|
||||
return false; \
|
||||
JSScript *script = GetScriptReferent(obj)
|
||||
|
||||
#define THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, fnname, args, obj, script) \
|
||||
THIS_DEBUGSCRIPT_SCRIPT_NEEDLIVE(cx, argc, vp, fnname, args, obj, script, false)
|
||||
#define THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, fnname, args, obj, script) \
|
||||
THIS_DEBUGSCRIPT_SCRIPT_NEEDLIVE(cx, argc, vp, fnname, args, obj, script, true)
|
||||
|
||||
static JSBool
|
||||
DebuggerScript_getUrl(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "get url", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getUrl", args, obj, script);
|
||||
|
||||
JSString *str = js_NewStringCopyZ(cx, script->filename);
|
||||
if (!str)
|
||||
|
@ -2036,7 +1918,7 @@ DebuggerScript_getUrl(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerScript_getStartLine(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "get startLine", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getStartLine", args, obj, script);
|
||||
args.rval().setNumber(script->lineno);
|
||||
return true;
|
||||
}
|
||||
|
@ -2044,25 +1926,17 @@ DebuggerScript_getStartLine(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerScript_getLineCount(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "get lineCount", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getLineCount", args, obj, script);
|
||||
|
||||
uintN maxLine = js_GetScriptLineExtent(script);
|
||||
args.rval().setNumber(jsdouble(maxLine));
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerScript_getLive(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "get live", args, obj, script);
|
||||
args.rval().setBoolean(!!script);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
DebuggerScript_getChildScripts(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "get live", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getChildScripts", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
|
||||
JSObject *result = NewDenseEmptyArray(cx);
|
||||
|
@ -2111,7 +1985,7 @@ static JSBool
|
|||
DebuggerScript_getOffsetLine(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debugger.Script.getOffsetLine", 1);
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "getOffsetLine", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getOffsetLine", args, obj, script);
|
||||
size_t offset;
|
||||
if (!ScriptOffset(cx, script, args[0], &offset))
|
||||
return false;
|
||||
|
@ -2271,7 +2145,7 @@ class FlowGraphSummary : public Vector<size_t> {
|
|||
static JSBool
|
||||
DebuggerScript_getAllOffsets(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "getAllOffsets", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getAllOffsets", args, obj, script);
|
||||
|
||||
/*
|
||||
* First pass: determine which offsets in this script are jump targets and
|
||||
|
@ -2329,7 +2203,7 @@ DebuggerScript_getAllOffsets(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerScript_getLineOffsets(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "getAllOffsets", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getLineOffsets", args, obj, script);
|
||||
REQUIRE_ARGC("Debugger.Script.getLineOffsets", 1);
|
||||
|
||||
/* Parse lineno argument. */
|
||||
|
@ -2378,7 +2252,7 @@ static JSBool
|
|||
DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debugger.Script.setBreakpoint", 2);
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "setBreakpoint", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
|
||||
JSObject *holder = GetScriptHolder(obj);
|
||||
|
@ -2414,7 +2288,7 @@ DebuggerScript_setBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerScript_getBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "getBreakpoints", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getBreakpoints", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
|
||||
jsbytecode *pc;
|
||||
|
@ -2451,7 +2325,7 @@ static JSBool
|
|||
DebuggerScript_clearBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debugger.Script.clearBreakpoint", 1);
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
|
||||
JSObject *handler = NonNullObject(cx, args[0]);
|
||||
|
@ -2466,7 +2340,7 @@ DebuggerScript_clearBreakpoint(JSContext *cx, uintN argc, Value *vp)
|
|||
static JSBool
|
||||
DebuggerScript_clearAllBreakpoints(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, argc, vp, "clearBreakpoint", args, obj, script);
|
||||
THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "clearAllBreakpoints", args, obj, script);
|
||||
Debugger *dbg = Debugger::fromChildJSObject(obj);
|
||||
script->compartment()->clearBreakpointsIn(cx, dbg, script, NULL);
|
||||
args.rval().setUndefined();
|
||||
|
@ -2484,7 +2358,6 @@ static JSPropertySpec DebuggerScript_properties[] = {
|
|||
JS_PSG("url", DebuggerScript_getUrl, 0),
|
||||
JS_PSG("startLine", DebuggerScript_getStartLine, 0),
|
||||
JS_PSG("lineCount", DebuggerScript_getLineCount, 0),
|
||||
JS_PSG("live", DebuggerScript_getLive, 0),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
|
@ -2759,17 +2632,12 @@ DebuggerFrame_getScript(JSContext *cx, uintN argc, Value *vp)
|
|||
}
|
||||
} else if (fp->isScriptFrame()) {
|
||||
/*
|
||||
* eval, JS_Evaluate*, and JS_ExecuteScript all create non-function
|
||||
* script frames. However, scripts for JS_ExecuteScript are held by
|
||||
* script objects, and must go in heldScripts, whereas scripts for eval
|
||||
* and JS_Evaluate* latter are explicitly destroyed when the call
|
||||
* returns, and must go in nonHeldScripts. Distinguish the two cases by
|
||||
* checking whether the script has a Script object allocated to it.
|
||||
* We got eval, JS_Evaluate*, or JS_ExecuteScript non-function script
|
||||
* frames.
|
||||
*/
|
||||
JSScript *script = fp->script();
|
||||
scriptObject = (script->u.object)
|
||||
? debug->wrapJSAPIScript(cx, script->u.object)
|
||||
: debug->wrapNonHeldScript(cx, script);
|
||||
scriptObject = debug->wrapScript(cx, script,
|
||||
script->isCachedEval ? NULL : script->u.object);
|
||||
if (!scriptObject)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -59,8 +59,6 @@ class Debugger {
|
|||
friend JSBool (::JS_DefineDebuggerObject)(JSContext *cx, JSObject *obj);
|
||||
|
||||
public:
|
||||
enum NewScriptKind { NewNonHeldScript, NewHeldScript };
|
||||
|
||||
enum Hook {
|
||||
OnDebuggerStatement,
|
||||
OnExceptionUnwind,
|
||||
|
@ -105,41 +103,14 @@ class Debugger {
|
|||
FrameMap;
|
||||
FrameMap frames;
|
||||
|
||||
typedef WeakMap<gc::Cell *, JSObject *, DefaultHasher<gc::Cell *>, CrossCompartmentMarkPolicy>
|
||||
CellWeakMap;
|
||||
|
||||
/* The map from debuggee objects to their Debugger.Object instances. */
|
||||
typedef WeakMap<JSObject *, JSObject *, DefaultHasher<JSObject *>, CrossCompartmentMarkPolicy>
|
||||
ObjectWeakMap;
|
||||
ObjectWeakMap objects;
|
||||
CellWeakMap objects;
|
||||
|
||||
/*
|
||||
* An ephemeral map from script-holding objects to Debugger.Script
|
||||
* instances.
|
||||
*/
|
||||
typedef WeakMap<JSObject *, JSObject *, DefaultHasher<JSObject *>, CrossCompartmentMarkPolicy>
|
||||
ScriptWeakMap;
|
||||
|
||||
/*
|
||||
* Map of Debugger.Script instances for garbage-collected JSScripts. For
|
||||
* function scripts, the key is the compiler-created, internal JSFunction;
|
||||
* for scripts returned by JSAPI functions, the key is the "Script"-class
|
||||
* JSObject.
|
||||
*/
|
||||
ScriptWeakMap heldScripts;
|
||||
|
||||
/*
|
||||
* An ordinary (non-ephemeral) map from JSScripts to Debugger.Script
|
||||
* instances, for non-held scripts that are explicitly freed.
|
||||
*/
|
||||
typedef HashMap<JSScript *, JSObject *, DefaultHasher<JSScript *>, RuntimeAllocPolicy>
|
||||
ScriptMap;
|
||||
|
||||
/*
|
||||
* Map from non-held JSScripts to their Debugger.Script objects. Non-held
|
||||
* scripts are scripts created for eval or JS_Evaluate* calls that are
|
||||
* explicitly destroyed when the call returns. Debugger.Script objects are
|
||||
* not strong references to such JSScripts; the Debugger.Script becomes
|
||||
* "dead" when the eval call returns.
|
||||
*/
|
||||
ScriptMap nonHeldScripts;
|
||||
/* An ephemeral map from JSScript* to Debugger.Script instances. */
|
||||
CellWeakMap scripts;
|
||||
|
||||
bool addDebuggeeGlobal(JSContext *cx, GlobalObject *obj);
|
||||
void removeDebuggeeGlobal(JSContext *cx, GlobalObject *global,
|
||||
|
@ -195,7 +166,7 @@ class Debugger {
|
|||
static void traceObject(JSTracer *trc, JSObject *obj);
|
||||
void trace(JSTracer *trc);
|
||||
static void finalize(JSContext *cx, JSObject *obj);
|
||||
static void markKeysInCompartment(JSTracer *tracer, const ObjectWeakMap &map);
|
||||
static void markKeysInCompartment(JSTracer *tracer, const CellWeakMap &map, bool scripts);
|
||||
|
||||
static Class jsclass;
|
||||
|
||||
|
@ -230,9 +201,7 @@ class Debugger {
|
|||
static void slowPathOnEnterFrame(JSContext *cx);
|
||||
static void slowPathOnLeaveFrame(JSContext *cx);
|
||||
static void slowPathOnNewScript(JSContext *cx, JSScript *script, JSObject *obj,
|
||||
NewScriptKind kind);
|
||||
static void slowPathOnDestroyScript(JSScript *script);
|
||||
|
||||
GlobalObject *compileAndGoGlobal);
|
||||
static JSTrapStatus dispatchHook(JSContext *cx, js::Value *vp, Hook which);
|
||||
|
||||
JSTrapStatus fireDebuggerStatement(JSContext *cx, Value *vp);
|
||||
|
@ -246,21 +215,12 @@ class Debugger {
|
|||
*/
|
||||
JSObject *newDebuggerScript(JSContext *cx, JSScript *script, JSObject *obj);
|
||||
|
||||
/* Helper function for wrapFunctionScript and wrapJSAPIscript. */
|
||||
JSObject *wrapHeldScript(JSContext *cx, JSScript *script, JSObject *obj);
|
||||
|
||||
/*
|
||||
* Receive a "new script" event from the engine. A new script was compiled
|
||||
* or deserialized. If kind is NewHeldScript, obj must be the holder
|
||||
* object. Otherwise, kind must be NewNonHeldScript, script must be an eval
|
||||
* or JS_Evaluate* script, and we must have
|
||||
* obj->getGlobal() == scopeObj->getGlobal()
|
||||
* where scopeObj is the scope in which the new script will be executed.
|
||||
* or deserialized. For eval scripts obj must be null, otherwise it must be
|
||||
* a script object.
|
||||
*/
|
||||
void fireNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScriptKind kind);
|
||||
|
||||
/* Remove script from our table of non-held scripts. */
|
||||
void destroyNonHeldScript(JSScript *script);
|
||||
void fireNewScript(JSContext *cx, JSScript *script, JSObject *obj);
|
||||
|
||||
static inline Debugger *fromLinks(JSCList *links);
|
||||
inline Breakpoint *firstBreakpoint() const;
|
||||
|
@ -302,8 +262,7 @@ class Debugger {
|
|||
static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp);
|
||||
static inline JSTrapStatus onExceptionUnwind(JSContext *cx, js::Value *vp);
|
||||
static inline void onNewScript(JSContext *cx, JSScript *script, JSObject *obj,
|
||||
NewScriptKind kind);
|
||||
static inline void onDestroyScript(JSScript *script);
|
||||
GlobalObject *compileAndGoGlobal);
|
||||
static JSTrapStatus onTrap(JSContext *cx, Value *vp);
|
||||
static JSTrapStatus onSingleStep(JSContext *cx, Value *vp);
|
||||
|
||||
|
@ -380,19 +339,12 @@ class Debugger {
|
|||
JSObject *wrapFunctionScript(JSContext *cx, JSFunction *fun);
|
||||
|
||||
/*
|
||||
* Return the Debugger.Script object for the Script object |obj|'s
|
||||
* JSScript, or create a new one if needed. The context |cx| must be in the
|
||||
* debugger compartment; |obj| must be a cross-compartment wrapper
|
||||
* referring to a script object in a debuggee compartment.
|
||||
* Return the Debugger.Script object for |script|, or create a new one if
|
||||
* needed. The context |cx| must be in the debugger compartment; |script| must
|
||||
* be a script in a debuggee compartment. |obj| is either the script holder or
|
||||
* null for non-held scripts.
|
||||
*/
|
||||
JSObject *wrapJSAPIScript(JSContext *cx, JSObject *scriptObj);
|
||||
|
||||
/*
|
||||
* Return the Debugger.Script object for the non-held script |script|, or
|
||||
* create a new one if needed. The context |cx| must be in the debugger
|
||||
* compartment; |script| must be a script in a debuggee compartment.
|
||||
*/
|
||||
JSObject *wrapNonHeldScript(JSContext *cx, JSScript *script);
|
||||
JSObject *wrapScript(JSContext *cx, JSScript *script, JSObject *obj);
|
||||
|
||||
private:
|
||||
/* Prohibit copying. */
|
||||
|
@ -413,7 +365,7 @@ class BreakpointSite {
|
|||
private:
|
||||
/*
|
||||
* The holder object for script, if known, else NULL. This is NULL for
|
||||
* non-held scripts and for JSD1 traps. It is always non-null for JSD2
|
||||
* cached eval scripts and for JSD1 traps. It is always non-null for JSD2
|
||||
* breakpoints in held scripts.
|
||||
*/
|
||||
JSObject *scriptObject;
|
||||
|
@ -564,18 +516,13 @@ Debugger::onExceptionUnwind(JSContext *cx, js::Value *vp)
|
|||
}
|
||||
|
||||
void
|
||||
Debugger::onNewScript(JSContext *cx, JSScript *script, JSObject *obj, NewScriptKind kind)
|
||||
Debugger::onNewScript(JSContext *cx, JSScript *script, JSObject *obj,
|
||||
GlobalObject *compileAndGoGlobal)
|
||||
{
|
||||
JS_ASSERT_IF(kind == NewHeldScript || script->compileAndGo, obj);
|
||||
JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
|
||||
JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
|
||||
if (!script->compartment()->getDebuggees().empty())
|
||||
slowPathOnNewScript(cx, script, obj, kind);
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::onDestroyScript(JSScript *script)
|
||||
{
|
||||
if (!script->compartment()->getDebuggees().empty())
|
||||
slowPathOnDestroyScript(script);
|
||||
slowPathOnNewScript(cx, script, obj, compileAndGoGlobal);
|
||||
}
|
||||
|
||||
extern JSBool
|
||||
|
|
Загрузка…
Ссылка в новой задаче