Bug 897919: Correctly de-lazify functions before trying to inspect their scripts. r=sfink
authorJim Blandy <jimb@mozilla.com>
Fri, 02 Aug 2013 20:27:22 -0700
changeset 141611 b27b567e0bdc82a95311b7f69f3c8a05c20429ef
parent 141610 19f48fd7faf1ba1a3b55a386a98e1204689c9c90
child 141612 5695cebb5c12a6bda4927efe48fdeb51568fd8d0
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssfink
bugs897919
milestone25.0a1
Bug 897919: Correctly de-lazify functions before trying to inspect their scripts. r=sfink
js/src/jit-test/tests/debug/Object-script-lazy.js
js/src/vm/Debugger.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-script-lazy.js
@@ -0,0 +1,34 @@
+// Asking for the script of a Debugger.Object whose referent is a lazy
+// function should work.
+
+// Note that putting a compartment in debug mode automatically de-lazifies
+// all its functions (so that findScripts works); so the only way to get a
+// Debugger.Object whose referent is a lazy function is to get one
+// referring to a non-debuggee function. (I don't think we should be
+// handing out non-debuggee scripts anyway.)
+
+// Create functions f, g in a non-debuggee compartment.
+var g1 = newGlobal();
+g1.eval('function f() { return "from f"; }');
+g1.eval('function g() { return "from g"; }');
+
+// Create a debuggee compartment with CCWs referring to f and g.
+var g2 = newGlobal();
+var dbg = new Debugger;
+var g2w = dbg.addDebuggee(g2);
+g2.f = g1.f;
+g2.g = g1.g;
+
+// At this point, g1.f should still be a lazy function. Unwrapping a D.O
+// referring to g2's CCW of f should yield a D.O referring to f directly.
+// Asking for that second D.O's script should de-lazify f.
+var fDO = g2w.getOwnPropertyDescriptor('f').value;
+assertEq(fDO.global, g2w);
+assertEq(fDO.unwrap().global === g2w, false);
+assertEq(fDO.unwrap().script instanceof Debugger.Script, true);
+
+// Similarly for g1.g, and asking for its parameter names.
+var gDO = g2w.getOwnPropertyDescriptor('g').value;
+assertEq(gDO.global, g2w);
+assertEq(gDO.unwrap().global === g2w, false);
+assertEq(gDO.unwrap().parameterNames instanceof Array, true);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4511,21 +4511,29 @@ DebuggerObject_getParameterNames(JSConte
 
     RootedFunction fun(cx, &obj->as<JSFunction>());
     JSObject *result = NewDenseAllocatedArray(cx, fun->nargs);
     if (!result)
         return false;
     result->ensureDenseInitializedLength(cx, 0, fun->nargs);
 
     if (fun->isInterpreted()) {
-        JS_ASSERT(fun->nargs == fun->nonLazyScript()->bindings.numArgs());
+        RootedScript script(cx);
+
+        {
+            AutoCompartment ac(cx, fun);
+            script = fun->getOrCreateScript(cx);
+            if (!script)
+                return false;
+        }
+
+        JS_ASSERT(fun->nargs == script->bindings.numArgs());
 
         if (fun->nargs > 0) {
             BindingVector bindings(cx);
-            RootedScript script(cx, fun->nonLazyScript());
             if (!FillBindingVector(script, &bindings))
                 return false;
             for (size_t i = 0; i < fun->nargs; i++) {
                 Value v;
                 if (bindings[i].name()->length() == 0)
                     v = UndefinedValue();
                 else
                     v = StringValue(bindings[i].name());
@@ -4552,17 +4560,26 @@ DebuggerObject_getScript(JSContext *cx, 
     }
 
     RootedFunction fun(cx, &obj->as<JSFunction>());
     if (fun->isBuiltin()) {
         args.rval().setUndefined();
         return true;
     }
 
-    RootedScript script(cx, fun->nonLazyScript());
+    RootedScript script(cx);
+
+    {
+        AutoCompartment ac(cx, obj);
+
+        script = fun->getOrCreateScript(cx);
+        if (!script)
+            return false;
+    }
+
     RootedObject scriptObject(cx, dbg->wrapScript(cx, script));
     if (!scriptObject)
         return false;
 
     args.rval().setObject(*scriptObject);
     return true;
 }