Fix another bug with getChildScripts: the relevant bit on JSScript was being set after the newScript hook was called. Set it beforehand instead.
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 07 Jul 2011 19:07:09 -0500
changeset 74505 2e006cccde9f5b6b2b42049bb4d2a01cfc832d84
parent 74504 75ec0d2c2c1fcd1873ea998309b425d105a97cd9
child 74506 94d505fb0a67cad3d3023fb9f1881e86631270b0
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone7.0a1
Fix another bug with getChildScripts: the relevant bit on JSScript was being set after the newScript hook was called. Set it beforehand instead.
js/src/jit-test/tests/debug/Script-getChildScripts-04.js
js/src/jit-test/tests/debug/hooks-newScript-01.js
js/src/jit-test/tests/debug/hooks-newScript-02.js
js/src/jsparse.cpp
js/src/jsscript.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getChildScripts-04.js
@@ -0,0 +1,17 @@
+// script.getChildScripts() works correctly during the newScript hook.
+// (A bug had it including the script for the calling function.)
+
+var g = newGlobal('new-compartment');
+g.eval("function h(a) { eval(a); }");
+
+var dbg = Debugger(g);
+var arr, kscript;
+dbg.hooks = {
+    newScript: function (script) { arr = script.getChildScripts(); },
+    debuggerHandler: function (frame) { kscript = frame.callee.script; }
+};
+
+g.h("function k(a) { debugger; return a + 1; } k(-1);");
+assertEq(kscript instanceof Debugger.Script, true);
+assertEq(arr.length, 1);
+assertEq(arr[0], kscript);
--- a/js/src/jit-test/tests/debug/hooks-newScript-01.js
+++ b/js/src/jit-test/tests/debug/hooks-newScript-01.js
@@ -1,23 +1,27 @@
 // Basic newScript hook tests.
 
 var g = newGlobal('new-compartment');
 var dbg = Debugger(g);
 var seen = WeakMap();
 var hits = 0;
 dbg.hooks = {
     newScript: function (s) {
+	// Exceptions thrown from newScript are swept under the rug, but they
+	// will at least prevent hits from being the expected number.
 	assertEq(s instanceof Debugger.Script, true);
 	assertEq(!seen.has(s), true);
 	seen.set(s, true);
 	hits++;
     }
 };
 
+dbg.uncaughtExceptionHook = function () { hits = -999; };
+
 // eval code
 hits = 0;
 assertEq(g.eval("2 + 2"), 4);
 assertEq(hits, 1);
 
 hits = 0;
 assertEq(g.eval("eval('2 + 3')"), 5);
 assertEq(hits, 2);
--- a/js/src/jit-test/tests/debug/hooks-newScript-02.js
+++ b/js/src/jit-test/tests/debug/hooks-newScript-02.js
@@ -8,16 +8,18 @@ dbg.hooks = {
     newScript: function (s) {
 	assertEq(s instanceof Debugger.Script, true);
 	assertEq(!seen.has(s), true);
 	seen.set(s, true);
 	hits++;
     }
 };
 
+dbg.uncaughtExceptionHook = function () { hits = -999; };
+
 function test(f) {
     hits = 0;
     f();
     assertEq(hits, 1);
 }
 
 // eval declaring a function
 test(function () { g.eval("function A(m, n) { return m===0?n+1:n===0?A(m-1,1):A(m-1,A(m,n-1)); }"); });
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -953,23 +953,20 @@ Compiler::compileScript(JSContext *cx, J
     /* If this is a direct call to eval, inherit the caller's strictness.  */
     if (callerFrame &&
         callerFrame->isScriptFrame() &&
         callerFrame->script()->strictModeCode) {
         cg.flags |= TCF_STRICT_MODE_CODE;
         tokenStream.setStrictMode();
     }
 
-    /*
-     * If funbox is non-null after we create the new script, callerFrame->fun
-     * was saved in the 0th object table entry.
-     */
-    JSObjectBox *funbox;
-    funbox = NULL;
-
+#ifdef DEBUG
+    bool savedCallerFun;
+    savedCallerFun = false;
+#endif
     if (tcflags & TCF_COMPILE_N_GO) {
         if (source) {
             /*
              * Save eval program source in script->atomMap.vector[0] for the
              * eval cache (see EvalCacheLookup in jsobj.cpp).
              */
             JSAtom *atom = js_AtomizeString(cx, source);
             jsatomid _;
@@ -978,22 +975,25 @@ Compiler::compileScript(JSContext *cx, J
         }
 
         if (callerFrame && callerFrame->isFunctionFrame()) {
             /*
              * An eval script in a caller frame needs to have its enclosing
              * function captured in case it refers to an upvar, and someone
              * wishes to decompile it while it's running.
              */
-            funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun()));
+            JSObjectBox *funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun()));
             if (!funbox)
                 goto out;
             funbox->emitLink = cg.objectList.lastbox;
             cg.objectList.lastbox = funbox;
             cg.objectList.length++;
+#ifdef DEBUG
+            savedCallerFun = true;
+#endif
         }
     }
 
     /*
      * Inline this->statements to emit as we go to save AST space. We must
      * generate our script-body blockid since we aren't calling Statements.
      */
     uint32 bodyid;
@@ -1106,18 +1106,17 @@ Compiler::compileScript(JSContext *cx, J
         goto out;
 
     JS_ASSERT(cg.version() == version);
 
     script = JSScript::NewScriptFromCG(cx, &cg);
     if (!script)
         goto out;
 
-    if (funbox)
-        script->savedCallerFun = true;
+    JS_ASSERT(script->savedCallerFun == savedCallerFun);
 
     {
         AutoShapeRooter shapeRoot(cx, script->bindings.lastShape());
         if (!defineGlobals(cx, globalScope, script))
             goto late_error;
     }
 
   out:
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1286,18 +1286,22 @@ JSScript::NewScriptFromCG(JSContext *cx,
     if (cg->constList.length() != 0)
         cg->constList.finish(script->consts());
     if (cg->flags & TCF_NO_SCRIPT_RVAL)
         script->noScriptRval = true;
     if (cg->hasSharps())
         script->hasSharps = true;
     if (cg->flags & TCF_STRICT_MODE_CODE)
         script->strictModeCode = true;
-    if (cg->flags & TCF_COMPILE_N_GO)
+    if (cg->flags & TCF_COMPILE_N_GO) {
         script->compileAndGo = true;
+        const StackFrame *fp = cg->parser->callerFrame;
+        if (fp && fp->isFunctionFrame())
+            script->savedCallerFun = true;
+    }
     if (cg->callsEval())
         script->usesEval = true;
     if (cg->flags & TCF_FUN_USES_ARGUMENTS)
         script->usesArguments = true;
     if (cg->flags & TCF_HAS_SINGLETONS)
         script->hasSingletons = true;
 
     if (cg->hasUpvarIndices()) {