Bug 1635839 - Part 3: Skip PrivateName symbols in iteration code. r=jorendorff
authorAndré Bargull <andre.bargull@gmail.com>
Tue, 02 Jun 2020 20:57:52 +0000
changeset 597700 2b34ab462221a4721c8ae08cc24e2b019c61a74a
parent 597699 e739f15aeaf8997dc22a28131b754c1a001e1deb
child 597701 851ee4729a31745d4845a584750f8858fcc0a455
push id13310
push userffxbld-merge
push dateMon, 29 Jun 2020 14:50:06 +0000
treeherdermozilla-beta@15a59a0afa5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1635839
milestone79.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1635839 - Part 3: Skip PrivateName symbols in iteration code. r=jorendorff Matthew Gaudet: Added Proxy test code Differential Revision: https://phabricator.services.mozilla.com/D74104
js/src/tests/non262/PrivateName/browser.js
js/src/tests/non262/PrivateName/not-iterable.js
js/src/tests/non262/PrivateName/shell.js
js/src/vm/Iteration.cpp
js/src/vm/SymbolType.h
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/browser.js
@@ -0,0 +1,3 @@
+if (typeof newPrivateName === "undefined") {
+  var newPrivateName = SpecialPowers.Cu.getJSTestingFunctions().newPrivateName;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/PrivateName/not-iterable.js
@@ -0,0 +1,35 @@
+// PrivateNames aren't iterable.
+
+var privateName = newPrivateName('');
+
+var o = {
+  [privateName]: 123,
+};
+
+assertEq(o[privateName], 123);
+
+assertEq(Object.keys(o).length, 0);
+assertEq(Object.getOwnPropertyNames(o).length, 0);
+assertEq(Object.getOwnPropertySymbols(o).length, 0);
+assertEq(Reflect.ownKeys(o).length, 0);
+
+var forIn = [];
+for (var pk in o) {
+  forIn.push(pk);
+}
+assertEq(forIn.length, 0);
+
+// Proxy case
+var proxy = new Proxy(o, {});
+assertEq(Object.keys(proxy).length, 0);
+assertEq(Object.getOwnPropertyNames(proxy).length, 0);
+assertEq(Object.getOwnPropertySymbols(proxy).length, 0);
+assertEq(Reflect.ownKeys(proxy).length, 0);
+
+for (var pk in proxy) {
+  forIn.push(pk);
+}
+assertEq(forIn.length, 0);
+
+if (typeof reportCompare === 'function')
+  reportCompare(0, 0);
new file mode 100644
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -120,20 +120,26 @@ static inline bool Enumerate(JSContext* 
   }
 
   if (!enumerable && !(flags & JSITER_HIDDEN)) {
     return true;
   }
 
   // Symbol-keyed properties and nonenumerable properties are skipped unless
   // the caller specifically asks for them. A caller can also filter out
-  // non-symbols by asking for JSITER_SYMBOLSONLY.
-  if (JSID_IS_SYMBOL(id) ? !(flags & JSITER_SYMBOLS)
-                         : (flags & JSITER_SYMBOLSONLY)) {
-    return true;
+  // non-symbols by asking for JSITER_SYMBOLSONLY. PrivateName symbols are
+  // always skipped.
+  if (JSID_IS_SYMBOL(id)) {
+    if (!(flags & JSITER_SYMBOLS) || JSID_TO_SYMBOL(id)->isPrivateName()) {
+      return true;
+    }
+  } else {
+    if ((flags & JSITER_SYMBOLSONLY)) {
+      return true;
+    }
   }
 
   return props.append(id);
 }
 
 static bool EnumerateExtraProperties(JSContext* cx, HandleObject obj,
                                      unsigned flags,
                                      MutableHandle<IdSet> visited,
@@ -390,16 +396,18 @@ struct SortComparatorIds {
     if (JSID_IS_INT(a)) {
       *lessOrEqualp = (JSID_TO_INT(a) <= JSID_TO_INT(b));
       return true;
     }
 
     RootedString astr(cx), bstr(cx);
     if (JSID_IS_SYMBOL(a)) {
       MOZ_ASSERT(JSID_IS_SYMBOL(b));
+      MOZ_ASSERT(!JSID_TO_SYMBOL(a)->isPrivateName());
+      MOZ_ASSERT(!JSID_TO_SYMBOL(b)->isPrivateName());
       JS::SymbolCode ca = JSID_TO_SYMBOL(a)->code();
       JS::SymbolCode cb = JSID_TO_SYMBOL(b)->code();
       if (ca != cb) {
         *lessOrEqualp = uint32_t(ca) <= uint32_t(cb);
         return true;
       }
       MOZ_ASSERT(ca == JS::SymbolCode::InSymbolRegistry ||
                  ca == JS::SymbolCode::UniqueSymbol);
--- a/js/src/vm/SymbolType.h
+++ b/js/src/vm/SymbolType.h
@@ -79,16 +79,19 @@ class Symbol : public js::gc::TenuredCel
   // that's often looked up on random objects but is usually not present. We
   // optimize this by setting a flag on the object's BaseShape when such
   // symbol properties are added, so we can optimize lookups on objects that
   // don't have the BaseShape flag.
   bool isInterestingSymbol() const {
     return code_ == SymbolCode::toStringTag || code_ == SymbolCode::toPrimitive;
   }
 
+  // Symbol created for the #PrivateName syntax.
+  bool isPrivateName() const { return code_ == SymbolCode::PrivateNameSymbol; }
+
   static const JS::TraceKind TraceKind = JS::TraceKind::Symbol;
   const js::gc::CellHeader& cellHeader() const { return headerAndDescription_; }
 
   inline void traceChildren(JSTracer* trc) {
     js::TraceNullableEdge(trc, &headerAndDescription_, "symbol description");
   }
   inline void finalize(JSFreeOp*) {}