Cross stack segment boundaries when looking for the youngest frame. Correctly check that live stack frames are on the stack.
authorJim Blandy <jimb@mozilla.com>
Wed, 08 Jun 2011 07:25:22 -0700
changeset 74466 ed51e6c81d01ff76f0aa7ec6e0046b2bc1c2d0c1
parent 74465 210f10efc3e47992e5e87010c1b948c9e3b14110
child 74467 b5d3c424d66d01df04121bd502cdfe5efb685428
push id20986
push userkhuey@mozilla.com
push dateSun, 14 Aug 2011 11:45:15 +0000
treeherdermozilla-central@2de3cff973b2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Cross stack segment boundaries when looking for the youngest frame. Correctly check that live stack frames are on the stack.
js/src/jsdbg.cpp
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -856,24 +856,25 @@ Debug::getDebuggees(JSContext *cx, uintN
     vp->setObject(*arrobj);
     return true;
 }
 
 JSBool
 Debug::getYoungestFrame(JSContext *cx, uintN argc, Value *vp)
 {
     THISOBJ(cx, vp, Debug, "getYoungestFrame", thisobj, dbg);
-    StackFrame *fp = cx->fp();
-    while (fp && !dbg->observesFrame(fp))
-        fp = fp->prev();
-    if (!fp) {
-        vp->setNull();
-        return true;
+
+    // cx->fp() would return the topmost frame in the current context.
+    // Since there may be multiple contexts, use AllFramesIter instead.
+    for (AllFramesIter i(cx); !i.done(); ++i) {
+        if (dbg->observesFrame(i.fp()))
+            return dbg->getScriptFrame(cx, i.fp(), vp);
     }
-    return dbg->getScriptFrame(cx, fp, vp);
+    vp->setNull();
+    return true;
 }
 
 JSBool
 Debug::construct(JSContext *cx, uintN argc, Value *vp)
 {
     // Check that the arguments, if any, are cross-compartment wrappers.
     Value *argv = vp + 2, *argvEnd = argv + argc;
     for (Value *p = argv; p != argvEnd; p++) {
@@ -1087,22 +1088,34 @@ CheckThisFrame(JSContext *cx, Value *vp,
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_FRAME_NOT_LIVE,
                                  "Debug.Frame", fnname);
             return NULL;
         }
     }
     return thisobj;
 }
 
+#if DEBUG
+static bool
+StackContains(JSContext *cx, StackFrame *fp)
+{
+    for (AllFramesIter i(cx); !i.done(); ++i) {
+        if (fp == i.fp())
+            return true;
+    }
+    return false;
+}
+#endif
+
 #define THIS_FRAME(cx, vp, fnname, thisobj, fp)                              \
     JSObject *thisobj = CheckThisFrame(cx, vp, fnname, true);                \
     if (!thisobj)                                                            \
         return false;                                                        \
     StackFrame *fp = (StackFrame *) thisobj->getPrivate();                   \
-    JS_ASSERT((cx)->stack.contains(fp))
+    JS_ASSERT(StackContains(cx, fp))
 
 static JSBool
 DebugFrame_getType(JSContext *cx, uintN argc, Value *vp)
 {
     THIS_FRAME(cx, vp, "get type", thisobj, fp);
 
     // Indirect eval frames are both isGlobalFrame() and isEvalFrame(), so the
     // order of checks here is significant.