jsdbg.cpp: Implement Debug.Object.prototype.parameterNames. Add tests. Also, change DebugObject_getName to follow return-on-error conventions.
authorJim Blandy <jimb@mozilla.com>
Mon, 23 May 2011 14:53:04 -0700
changeset 74444 2a6c013ce9e7573be3d8cbfc5991544a0bd97050
parent 74443 6d94e6ad3858ed12244de433385faa4d593017d4
child 74445 1fb7cb53a55514180b0b83e003cc611fd86b4d20
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone6.0a1
jsdbg.cpp: Implement Debug.Object.prototype.parameterNames. Add tests. Also, change DebugObject_getName to follow return-on-error conventions.
js/src/jit-test/tests/debug/Object-parameterNames.js
js/src/jscntxt.h
js/src/jsdbg.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-parameterNames.js
@@ -0,0 +1,36 @@
+// |jit-test| debug
+load(libdir + 'array-compare.js');
+
+var g = newGlobal('new-compartment');
+var dbg = new Debug(g);
+var hits = 0;
+dbg.hooks = {
+    debuggerHandler: function (frame) {
+        var arr = frame.arguments;
+        assertEq(arraysEqual(arr[0].parameterNames, []), true);
+        assertEq(arraysEqual(arr[1].parameterNames, ["x"]), true);
+        assertEq(arraysEqual(arr[2].parameterNames,
+                             ["a","b","c","d","e","f","g","h","i","j","k","l","m",
+                              "n","o","p","q","r","s","t","u","v","w","x","y","z"]), 
+                 true);
+        assertEq(arraysEqual(arr[3].parameterNames, ["a", (void 0), (void 0)]), true);
+        assertEq(arr[4].parameterNames, (void 0));
+        assertEq(arraysEqual(arr[5].parameterNames, [(void 0), (void 0)]), true);
+        assertEq(arr.length, 6);
+        hits++;
+    }
+};
+
+g.eval("("
+       + function () { 
+           (function () { debugger; }
+            (function () {},
+             function (x) {},
+             function (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) {},
+             function (a, [b, c], {d, e:f}) { },
+             {a:1},
+             Math.atan2
+            ));
+       }
+       +")()");
+assertEq(hits, 1);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -2004,17 +2004,17 @@ class AutoReleaseNullablePtr {
             cx->free_(ptr);
         ptr = ptr2;
     }
     ~AutoReleaseNullablePtr() { if (ptr) cx->free_(ptr); }
 };
 
 class AutoLocalNameArray {
   public:
-    explicit AutoLocalNameArray(JSContext *cx, JSFunction *fun
+    explicit AutoLocalNameArray(JSContext *cx, const JSFunction *fun
                                 JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : context(cx),
         mark(JS_ARENA_MARK(&cx->tempPool)),
         names(fun->script()->bindings.getLocalNameArray(cx, &cx->tempPool)),
         count(fun->script()->bindings.countLocalNames())
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
--- a/js/src/jsdbg.cpp
+++ b/js/src/jsdbg.cpp
@@ -1308,23 +1308,68 @@ DebugObject_getCallable(JSContext *cx, u
     vp->setBoolean(refobj->isCallable());
     return true;
 }
 
 static JSBool
 DebugObject_getName(JSContext *cx, uintN argc, Value *vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, vp, "get name", obj);
-    if (obj->isFunction()) {
-        if (JSString *name = obj->getFunctionPrivate()->atom) {
-            vp->setString(name);
-            return Debug::fromChildJSObject(&vp[1].toObject())->wrapDebuggeeValue(cx, vp);
+    if (!obj->isFunction()) {
+        vp->setNull();
+        return true;
+    }
+
+    JSString *name = obj->getFunctionPrivate()->atom;
+    if (!name) {
+        vp->setNull();
+        return true;
+    }
+        
+    vp->setString(name);
+    return Debug::fromChildJSObject(&vp[1].toObject())->wrapDebuggeeValue(cx, vp);
+}
+
+static JSBool
+DebugObject_getParameterNames(JSContext *cx, uintN argc, Value *vp)
+{
+    THIS_DEBUGOBJECT_REFERENT(cx, vp, "get parameterNames", obj);
+    if (!obj->isFunction()) {
+        vp->setUndefined();
+        return true;
+    }
+
+    const JSFunction *fun = obj->getFunctionPrivate();
+    JSObject *result = NewDenseAllocatedArray(cx, fun->nargs, NULL);
+    if (!result)
+        return false;
+
+    if (fun->isInterpreted()) {
+        JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
+
+        if (fun->nargs > 0) {
+            const AutoLocalNameArray names(cx, fun);
+            if (!names)
+                return false;
+
+            for (size_t i = 0; i < fun->nargs; i++) {
+                JSAtom *name = JS_LOCAL_NAME_TO_ATOM(names[i]);
+                Value *elt = result->addressOfDenseArrayElement(i);
+                if (name)
+                    elt->setString(name);
+                else
+                    elt->setUndefined();
+            }
         }
+    } else {
+        for (size_t i = 0; i < fun->nargs; i++)
+            result->addressOfDenseArrayElement(i)->setUndefined();
     }
-    vp->setNull();
+
+    vp->setObject(*result);
     return true;
 }
 
 static JSBool
 DebugObject_apply(JSContext *cx, uintN argc, Value *vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, vp, "apply", obj);
     Debug *dbg = Debug::fromChildJSObject(&vp[1].toObject());
@@ -1380,16 +1425,17 @@ DebugObject_apply(JSContext *cx, uintN a
     return dbg->newCompletionValue(ac, ok, rval, vp);
 }
 
 static JSPropertySpec DebugObject_properties[] = {
     JS_PSG("proto", DebugObject_getProto, 0),
     JS_PSG("class", DebugObject_getClass, 0),
     JS_PSG("callable", DebugObject_getCallable, 0),
     JS_PSG("name", DebugObject_getName, 0),
+    JS_PSG("parameterNames", DebugObject_getParameterNames, 0),
     JS_PS_END
 };
 
 static JSFunctionSpec DebugObject_methods[] = {
     JS_FN("apply", DebugObject_apply, 0, 0),
     JS_FS_END
 };