Add Debug.Frame.prototype.older.

This commit is contained in:
Jason Orendorff 2011-05-04 13:08:51 -05:00
parent 03415943ee
commit 5dc65a5a16
4 changed files with 115 additions and 23 deletions

View File

@ -0,0 +1,52 @@
// |jit-test| debug
// Test that we create new Debug.Frames and reuse old ones correctly with recursion.
var g = newGlobal('new-compartment');
g.debuggeeGlobal = this;
g.eval("(" + function () {
function id(f) {
return ("id" in f) ? f.id : (f.id = nextid++);
}
var dbg = new Debug(debuggeeGlobal);
dbg.hooks = {
debuggerHandler: function (frame) {
var a = [];
for (; frame; frame = frame.older)
a.push(frame);
var s = '';
while (a.length)
s += id(a.pop());
results.push(s);
}
};
} + ")();");
function cons(a, b) {
debugger;
return [a, b];
}
function tree(n) {
if (n < 2)
return n;
return cons(tree(n - 1), tree(n - 2));
}
g.eval("results = []; nextid = 0;");
debugger;
assertEq(g.results.join(","), "0");
assertEq(g.nextid, 1);
g.eval("results = [];");
tree(2);
assertEq(g.results.join(","), "012"); // 0=global, 1=tree, 2=cons
g.eval("results = []; nextid = 1;");
tree(3);
assertEq(g.results.join(","), "0123,014"); //0=global, 1=tree(3), 2=tree(2), 3=cons, 4=cons
g.eval("results = []; nextid = 1;");
tree(4);
// 0=global, 1=tree(4), 2=tree(3), 3=tree(2), 4=cons, tree(1), 5=cons, 6=tree(2), 7=cons, 8=cons
assertEq(g.results.join(","), "01234,0125,0167,018");

View File

@ -0,0 +1,25 @@
// |jit-test| debug
// Basic call chain.
var g = newGlobal('new-compartment');
g.debuggeeGlobal = this;
g.result = null;
g.eval("(" + function () {
var dbg = new Debug(debuggeeGlobal);
dbg.hooks = {
debuggerHandler: function (frame) {
var a = [];
assertEq(frame === frame.older, false);
for (; frame; frame = frame.older)
a.push(frame.type === 'call' ? frame.callee.name : frame.type);
a.reverse();
result = a.join(", ");
}
};
} + ")();");
function first() { return second(); }
function second() { return eval("third()"); }
function third() { debugger; }
first();
assertEq(g.result, "global, first, second, eval, third");

View File

@ -149,9 +149,22 @@ Debug::init()
return frames.init() && objects.init();
}
JS_STATIC_ASSERT(uintN(JSSLOT_DEBUGFRAME_OWNER) == uintN(JSSLOT_DEBUGOBJECT_OWNER));
Debug *
Debug::fromChildJSObject(JSObject *obj)
{
JS_ASSERT(obj->clasp == &DebugFrame_class ||
obj->clasp == &DebugObject_class ||
obj->clasp == &DebugFunction_class);
JSObject *dbgobj = &obj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER).toObject();
return fromJSObject(dbgobj);
}
bool
Debug::getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp)
{
JS_ASSERT(fp->isScriptFrame());
FrameMap::AddPtr p = frames.lookupForAdd(fp);
if (!p) {
// Create script frame. First copy the arguments.
@ -734,28 +747,12 @@ DebugFrame_getType(JSContext *cx, uintN argc, Value *vp)
return true;
}
JS_STATIC_ASSERT(uintN(JSSLOT_DEBUGFRAME_OWNER) == uintN(JSSLOT_DEBUGOBJECT_OWNER));
static JSBool
DebugChild_wrapDebuggeeValue(JSContext *cx, JSObject *frameobj, Value *vp)
{
// This uses JSSLOT_DEBUGOBJECT_OWNER, but it will work for any object that
// has a pointer to the owning Debug object in reserved slot 0.
JSObject *dbgobj = &frameobj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER).toObject();
Debug *dbg = Debug::fromJSObject(dbgobj);
if (!dbg->wrapDebuggeeValue(cx, vp)) {
vp->setUndefined();
return false;
}
return true;
}
static JSBool
DebugFrame_getCallee(JSContext *cx, uintN argc, Value *vp)
{
THIS_FRAME(cx, vp, "get callee", thisobj, fp);
*vp = (fp->isFunctionFrame() && !fp->isEvalFrame()) ? fp->calleev() : NullValue();
return DebugChild_wrapDebuggeeValue(cx, thisobj, vp);
return Debug::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, vp);
}
static JSBool
@ -779,7 +776,19 @@ DebugFrame_getThis(JSContext *cx, uintN argc, Value *vp)
*vp = fp->thisValue();
ac.leave();
}
return DebugChild_wrapDebuggeeValue(cx, thisobj, vp);
return Debug::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, vp);
}
static JSBool
DebugFrame_getOlder(JSContext *cx, uintN argc, Value *vp)
{
THIS_FRAME(cx, vp, "get this", thisobj, thisfp);
for (StackFrame *fp = thisfp->prev(); fp; fp = fp->prev()) {
if (!fp->isDummyFrame())
return Debug::fromChildJSObject(thisobj)->getScriptFrame(cx, fp, vp);
}
vp->setNull();
return true;
}
JSBool
@ -811,11 +820,12 @@ DebugFrame_construct(JSContext *cx, uintN argc, Value *vp)
static JSPropertySpec DebugFrame_properties[] = {
JS_PSG("type", DebugFrame_getType, 0),
JS_PSG("this", DebugFrame_getThis, 0),
JS_PSG("older", DebugFrame_getOlder, 0),
JS_PSG("live", DebugFrame_getLive, 0),
JS_PSG("callee", DebugFrame_getCallee, 0),
JS_PSG("generator", DebugFrame_getGenerator, 0),
JS_PSG("this", DebugFrame_getThis, 0),
JS_PSG("arguments", DebugFrame_getArguments, 0),
JS_PSG("live", DebugFrame_getLive, 0),
JS_PS_END
};
@ -922,7 +932,7 @@ DebugFunction_getName(JSContext *cx, uintN argc, Value *vp)
THIS_DEBUGFUNCTION_REFERENT(cx, vp, "get name", funobj);
if (JSString *name = funobj->getFunctionPrivate()->atom) {
vp->setString(name);
return DebugChild_wrapDebuggeeValue(cx, &vp[1].toObject(), vp);
return Debug::fromChildJSObject(&vp[1].toObject())->wrapDebuggeeValue(cx, vp);
}
vp->setNull();
return true;

View File

@ -92,7 +92,6 @@ class Debug {
inline bool hasAnyLiveHooks() const;
bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
static void slowPathLeaveStackFrame(JSContext *cx);
inline bool observesDebuggerStatement() const;
@ -104,8 +103,10 @@ class Debug {
bool init();
inline JSObject *toJSObject() const;
static inline Debug *fromJSObject(JSObject *obj);
static Debug *fromChildJSObject(JSObject *obj);
/*********************************** Methods for interaction with the GC. */
// Methods for interaction with the GC.
//
// A Debug object is live if:
// * the Debug JSObject is live (Debug::trace handles this case); OR
@ -131,6 +132,8 @@ class Debug {
static inline void leaveStackFrame(JSContext *cx);
static inline JSTrapStatus onDebuggerStatement(JSContext *cx, js::Value *vp);
/**************************************** Functions for use by jsdbg.cpp. */
// Precondition: *vp is a value from a debuggee compartment and cx is in
// the debugger's compartment.
//
@ -151,6 +154,8 @@ class Debug {
//
bool unwrapDebuggeeValue(JSContext *cx, Value *vp);
// Store the Debug.Frame object for the frame fp in *vp.
bool getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp);
};
bool