Fix bug in Debugger.Script.prototype.getChildScripts. It didn't know about JSScript::savedCallerFun.
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 07 Jul 2011 17:52:39 -0500
changeset 74503 53d431ddc5ac1ea56d9221fa29a4154c13ab553b
parent 74502 93e47625c3ed8cc43095b86847512b516d5dceb5
child 74504 75ec0d2c2c1fcd1873ea998309b425d105a97cd9
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone7.0a1
Fix bug in Debugger.Script.prototype.getChildScripts. It didn't know about JSScript::savedCallerFun.
js/src/jit-test/tests/debug/Script-getChildScripts-03.js
js/src/jsdbg.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getChildScripts-03.js
@@ -0,0 +1,18 @@
+// getChildScripts on a direct eval script returns the right scripts.
+// (A bug had it also returning the script for the calling function.)
+
+var g = newGlobal('new-compartment');
+var dbg = Debugger(g);
+var hits = 0;
+dbg.hooks = {
+    debuggerHandler: function (frame) {
+	var arr = frame.script.getChildScripts();
+	assertEq(arr.length, 1);
+	assertEq(arr[0], frame.eval("h").return.script);
+	hits++;
+    }
+};
+
+g.eval("function f(s) { eval(s); }");
+g.f("debugger; function h(a) { return a + 1; }");
+assertEq(hits, 1);
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -1706,18 +1706,21 @@ DebuggerScript_getChildScripts(JSContext
 {
     THIS_DEBUGSCRIPT_LIVE_SCRIPT(cx, vp, "get live", obj, script);
     Debugger *dbg = Debugger::fromChildJSObject(obj);
 
     JSObject *result = NewDenseEmptyArray(cx);
     if (!result)
         return false;
     if (JSScript::isValidOffset(script->objectsOffset)) {
+        // script->savedCallerFun indicates that this is a direct eval script
+        // and the calling function is stored as script->objects()->vector[0].
+        // It is not really a child script of this script, so skip it.
         JSObjectArray *objects = script->objects();
-        for (uint32 i = 0; i < objects->length; i++) {
+        for (uint32 i = script->savedCallerFun ? 1 : 0; i < objects->length; i++) {
             JSObject *obj = objects->vector[i];
             if (obj->isFunction()) {
                 JSObject *s = dbg->wrapFunctionScript(cx, (JSFunction *) obj);
                 if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
                     return false;
             }
         }
     }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -994,17 +994,17 @@ EvalCacheLookup(JSContext *cx, JSLinearS
             !script->hasSingletons &&
             (script->principals == principals ||
              (principals->subsume(principals, script->principals) &&
               script->principals->subsume(script->principals, principals)))) {
             /*
              * Get the prior (cache-filling) eval's saved caller function.
              * See Compiler::compileScript in jsparse.cpp.
              */
-            JSFunction *fun = script->getFunction(0);
+            JSFunction *fun = script->getCallerFunction();
 
             if (fun == caller->fun()) {
                 /*
                  * Get the source string passed for safekeeping in the
                  * atom map by the prior eval to Compiler::compileScript.
                  */
                 JSAtom *src = script->atomMap.vector[0];
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -2911,20 +2911,18 @@ Decompile(SprintStack *ss, jsbytecode *p
                 break;
               }
 
               case JSOP_GETUPVAR_DBG:
               case JSOP_CALLUPVAR_DBG:
               case JSOP_GETFCSLOT:
               case JSOP_CALLFCSLOT:
               {
-                if (!jp->fun) {
-                    JS_ASSERT(jp->script->savedCallerFun);
-                    jp->fun = jp->script->getFunction(0);
-                }
+                if (!jp->fun)
+                    jp->fun = jp->script->getCallerFunction();
 
                 if (!jp->localNames) {
                     JS_ASSERT(fun == jp->fun);
                     jp->localNames = cx->new_<Vector<JSAtom *> >(cx);
                     if (!jp->localNames ||
                         !jp->fun->script()->bindings.getLocalNameArray(cx, jp->localNames))
                     {
                         return NULL;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -466,17 +466,17 @@ struct JSScript {
     uint8           regexpsOffset;  /* offset to the array of to-be-cloned
                                        regexps  */
     uint8           trynotesOffset; /* offset to the array of try notes */
     uint8           globalsOffset;  /* offset to the array of global slots */
     uint8           constOffset;    /* offset to the array of constants */
 
     bool            noScriptRval:1; /* no need for result value of last
                                        expression statement */
-    bool            savedCallerFun:1; /* object 0 is caller function */
+    bool            savedCallerFun:1; /* can call getCallerFunction() */
     bool            hasSharps:1;      /* script uses sharp variables */
     bool            strictModeCode:1; /* code is in strict mode */
     bool            compileAndGo:1;   /* script was compiled with TCF_COMPILE_N_GO */
     bool            usesEval:1;       /* script uses eval() */
     bool            usesArguments:1;  /* script uses arguments */
     bool            warnedAboutTwoArgumentEval:1; /* have warned about use of
                                                      obsolete eval(s, o) in
                                                      this script */
@@ -628,16 +628,17 @@ struct JSScript {
         return getAtom(arr->vector[index].atomIndex);
     }
 
     JSVersion getVersion() const {
         return JSVersion(version);
     }
 
     inline JSFunction *getFunction(size_t index);
+    inline JSFunction *getCallerFunction();
 
     inline JSObject *getRegExp(size_t index);
 
     const js::Value &getConst(size_t index) {
         JSConstArray *arr = consts();
         JS_ASSERT(index < arr->length);
         return arr->vector[index];
     }
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -119,16 +119,23 @@ JSScript::getFunction(size_t index)
     JSObject *funobj = getObject(index);
     JS_ASSERT(funobj->isFunction());
     JS_ASSERT(funobj == (JSObject *) funobj->getPrivate());
     JSFunction *fun = (JSFunction *) funobj;
     JS_ASSERT(FUN_INTERPRETED(fun));
     return fun;
 }
 
+inline JSFunction *
+JSScript::getCallerFunction()
+{
+    JS_ASSERT(savedCallerFun);
+    return getFunction(0);
+}
+
 inline JSObject *
 JSScript::getRegExp(size_t index)
 {
     JSObjectArray *arr = regexps();
     JS_ASSERT((uint32) index < arr->length);
     JSObject *obj = arr->vector[index];
     JS_ASSERT(obj->getClass() == &js_RegExpClass);
     return obj;