Bug 1035973 - Add DebuggerObject.getOwnPropertySymbols; r=fitzgen
authorManish Goregaokar <manishearth@gmail.com>
Tue, 16 Jun 2015 09:30:00 +0200
changeset 267445 8c7ba866689033f77768d2d784ca8e64cfece6ed
parent 267444 264d12cfb07363c3cf239afac1a738f1eb27967b
child 267446 e8c686e09998959582a470b2fd6c87fd15f1732e
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-esr52@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfitzgen
bugs1035973
milestone41.0a1
Bug 1035973 - Add DebuggerObject.getOwnPropertySymbols; r=fitzgen
js/src/doc/Debugger/Debugger.Object.md
js/src/jit-test/tests/debug/Object-getOwnPropertyNames-02.js
js/src/jit-test/tests/debug/Object-getOwnPropertySymbols-01.js
js/src/jit-test/tests/debug/Object-getOwnPropertySymbols-02.js
js/src/vm/Debugger.cpp
--- a/js/src/doc/Debugger/Debugger.Object.md
+++ b/js/src/doc/Debugger/Debugger.Object.md
@@ -243,16 +243,22 @@ code), the call throws a [`Debugger.Debu
     if present, are debuggee values.)
 
 `getOwnPropertyNames()`
 :   Return an array of strings naming all the referent's own properties, as
     if <code>Object.getOwnPropertyNames(<i>referent</i>)</code> had been
     called in the debuggee, and the result copied in the scope of the
     debugger's global object.
 
+`getOwnPropertySymbols()`
+:   Return an array of strings naming all the referent's own symbols, as
+    if <code>Object.getOwnPropertySymbols(<i>referent</i>)</code> had been
+    called in the debuggee, and the result copied in the scope of the
+    debugger's global object.
+
 <code>defineProperty(<i>name</i>, <i>attributes</i>)</code>
 :   Define a property on the referent named <i>name</i>, as described by
     the property descriptor <i>descriptor</i>. Any `value`, `get`, and
     `set` properties of <i>attributes</i> must be debuggee values. (This
     function behaves like `Object.defineProperty`, except that the target
     object is implicit, and in a different compartment from the function
     and descriptor.)
 
--- a/js/src/jit-test/tests/debug/Object-getOwnPropertyNames-02.js
+++ b/js/src/jit-test/tests/debug/Object-getOwnPropertyNames-02.js
@@ -4,9 +4,8 @@ var g = newGlobal();
 var dbg = Debugger();
 var gobj = dbg.addDebuggee(g);
 g.p = {xyzzy: 8};  // makes a cross-compartment wrapper
 g.p[Symbol.for("plugh")] = 9;
 var wp = gobj.getOwnPropertyDescriptor("p").value;
 var names = wp.getOwnPropertyNames();
 assertEq(names.length, 1);
 assertEq(names[0], "xyzzy");
-
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-getOwnPropertySymbols-01.js
@@ -0,0 +1,33 @@
+// Basic getOwnPropertSymbols tests.
+
+var g = newGlobal();
+var dbg = Debugger();
+var gobj = dbg.addDebuggee(g);
+
+function test(code) {
+    code = "(" + code + ");";
+    var expected = Object.getOwnPropertySymbols(eval(code));
+    g.eval("obj = " + code);
+    var actual = gobj.getOwnPropertyDescriptor("obj").value.getOwnPropertySymbols();
+
+    assertEq(JSON.stringify(actual.map((x) => x.toString()).sort()),
+             JSON.stringify(expected.map((x) => x.toString()).sort()));
+}
+
+test("{}");
+test("Array.prototype"); // Symbol.iterator
+test("Object.create(null)");
+test("(function() {let x = Symbol(); let o = {}; o[x] = 1; return o;})()");
+test("(function() {let x = Symbol('foo'); let o = {}; o[x] = 1; return o;})()");
+test("(function() {let x = Symbol('foo'); let y = Symbol('bar'); \
+                   let o = {}; o[x] = 1; o[y] = 2; return o;})()");
+test("(function() {let x = Symbol('foo with spaces'); \
+      let o = {}; o[x] = 1; return o;})()");
+test("(function() {let x = Symbol('foo'); \
+      let o = function(){}; o[x] = 1; return o;})()");
+test("(function() {let x = Symbol('foo'); \
+      let o = Object.create(null); o[x] = 1; return o;})()");
+test("(function() {let x = Symbol('foo'); \
+      let o = new Array(); o[x] = 1; return o;})()");
+test("(function() {let x = Symbol('foo'); \
+      let o = {}; o[x] = 1; delete o[x]; return o;})()");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-getOwnPropertySymbols-02.js
@@ -0,0 +1,12 @@
+// obj.getOwnPropertySymbols() works when obj's referent is itself a cross-compartment wrapper.
+
+var g = newGlobal();
+var dbg = Debugger();
+var gobj = dbg.addDebuggee(g);
+g.p = {xyzzy: 8};  // makes a cross-compartment wrapper
+var sym = Symbol("plugh");
+g.p[sym] = 9;
+var wp = gobj.getOwnPropertyDescriptor("p").value;
+var names = wp.getOwnPropertySymbols();
+assertEq(names.length, 1);
+assertEq(names[0], sym);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6932,56 +6932,70 @@ DebuggerObject_getOwnPropertyDescriptor(
                 return false;
             desc.setSetterObject(set.toObjectOrNull());
         }
     }
 
     return FromPropertyDescriptor(cx, desc, args.rval());
 }
 
+
 static bool
-DebuggerObject_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp)
-{
-    THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "getOwnPropertyNames", args, obj);
-
+getOwnPropertyKeys(JSContext* cx, unsigned argc, unsigned flags, Value* vp)
+{
+    THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "getOwnPropertyKeys", args, obj);
     AutoIdVector keys(cx);
     {
         Maybe<AutoCompartment> ac;
         ac.emplace(cx, obj);
         ErrorCopier ec(ac);
-        if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
+        if (!GetPropertyKeys(cx, obj, flags, &keys))
             return false;
     }
 
     AutoValueVector vals(cx);
     if (!vals.resize(keys.length()))
         return false;
 
     for (size_t i = 0, len = keys.length(); i < len; i++) {
          jsid id = keys[i];
          if (JSID_IS_INT(id)) {
              JSString* str = Int32ToString<CanGC>(cx, JSID_TO_INT(id));
              if (!str)
                  return false;
              vals[i].setString(str);
          } else if (JSID_IS_ATOM(id)) {
              vals[i].setString(JSID_TO_STRING(id));
+         } else if (JSID_IS_SYMBOL(id)) {
+             vals[i].setSymbol(JSID_TO_SYMBOL(id));
          } else {
-             MOZ_ASSERT_UNREACHABLE("GetPropertyKeys must return only string and int jsids");
+             MOZ_ASSERT_UNREACHABLE("GetPropertyKeys must return only string, int, and Symbol jsids");
          }
     }
 
     JSObject* aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
     if (!aobj)
         return false;
     args.rval().setObject(*aobj);
     return true;
 }
 
 static bool
+DebuggerObject_getOwnPropertyNames(JSContext* cx, unsigned argc, Value* vp) {
+    return getOwnPropertyKeys(cx, argc, JSITER_OWNONLY | JSITER_HIDDEN, vp);
+}
+
+static bool
+DebuggerObject_getOwnPropertySymbols(JSContext* cx, unsigned argc, Value* vp) {
+    return getOwnPropertyKeys(cx, argc,
+                              JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY,
+                              vp);
+}
+
+static bool
 DebuggerObject_defineProperty(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "defineProperty", args, dbg, obj);
     if (!args.requireAtLeast(cx, "Debugger.Object.defineProperty", 2))
         return false;
 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, args[0], &id))
@@ -7403,16 +7417,17 @@ static const JSPropertySpec DebuggerObje
     JS_PSG("global", DebuggerObject_getGlobal, 0),
     JS_PSG("allocationSite", DebuggerObject_getAllocationSite, 0),
     JS_PS_END
 };
 
 static const JSFunctionSpec DebuggerObject_methods[] = {
     JS_FN("getOwnPropertyDescriptor", DebuggerObject_getOwnPropertyDescriptor, 1, 0),
     JS_FN("getOwnPropertyNames", DebuggerObject_getOwnPropertyNames, 0, 0),
+    JS_FN("getOwnPropertySymbols", DebuggerObject_getOwnPropertySymbols, 0, 0),
     JS_FN("defineProperty", DebuggerObject_defineProperty, 2, 0),
     JS_FN("defineProperties", DebuggerObject_defineProperties, 1, 0),
     JS_FN("deleteProperty", DebuggerObject_deleteProperty, 1, 0),
     JS_FN("seal", DebuggerObject_seal, 0, 0),
     JS_FN("freeze", DebuggerObject_freeze, 0, 0),
     JS_FN("preventExtensions", DebuggerObject_preventExtensions, 0, 0),
     JS_FN("isSealed", DebuggerObject_isSealed, 0, 0),
     JS_FN("isFrozen", DebuggerObject_isFrozen, 0, 0),