diff --git a/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js b/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js new file mode 100644 index 000000000000..ad6e1845e154 --- /dev/null +++ b/js/src/jit-test/tests/proxy/testDirectProxyOwnKeysSymbol.js @@ -0,0 +1,33 @@ +// Make sure that we can find own, enumerable symbols. +var symbol = Symbol("bad"); +var symbol2 = Symbol("good"); +var proxy = new Proxy({}, { + ownKeys() { + return [symbol, symbol2]; + }, + getOwnPropertyDescriptor(target, name) { + if (name == symbol) + return {configurable: true, enumerable: false, value: {}}; + // Only this enumerable symbol should be defined. + if (name == symbol2) + return {configurable: true, enumerable: true, value: {}}; + assertEq(true, false); + }, + get(target, name) { + // Slightly confusing, but these are the descriptors that defineProperties + // is going to define on the object. + if (name == symbol) + return {configurable: true, value: "bad"}; + if (name == symbol2) + return {configurable: true, value: "good"}; + assertEq(true, false); + } +}); +assertEq(Object.getOwnPropertySymbols(proxy).length, 2); + +var obj = {}; +Object.defineProperties(obj, proxy); +assertEq(Object.getOwnPropertySymbols(obj).length, 1); +assertEq(symbol in obj, false); +assertEq(symbol2 in obj, true); +assertEq(obj[symbol2], "good"); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 049e21c062a2..d7d39ebcc758 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -312,14 +312,31 @@ Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props) // will filter out unwanted keys, per the flags. if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps)) return false; + + Rooted desc(cx); + for (size_t n = 0, len = proxyProps.length(); n < len; n++) { + bool enumerable = false; + + // We need to filter, if the caller just wants enumerable + // symbols. + if (!(flags & JSITER_HIDDEN)) { + if (!Proxy::getOwnPropertyDescriptor(cx, pobj, proxyProps[n], &desc)) + return false; + enumerable = desc.isEnumerable(); + } + + if (!Enumerate(cx, pobj, proxyProps[n], enumerable, flags, ht, props)) + return false; + } } else { + // Returns enumerable property names (no symbols). if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps)) return false; - } - for (size_t n = 0, len = proxyProps.length(); n < len; n++) { - if (!Enumerate(cx, pobj, proxyProps[n], true, flags, ht, props)) - return false; + for (size_t n = 0, len = proxyProps.length(); n < len; n++) { + if (!Enumerate(cx, pobj, proxyProps[n], true, flags, ht, props)) + return false; + } } } else { MOZ_CRASH("non-native objects must have an enumerate op"); diff --git a/js/src/tests/js1_8_5/regress/regress-620376-1.js b/js/src/tests/js1_8_5/regress/regress-620376-1.js index 3bb60af43c6a..9fa6b889f43d 100644 --- a/js/src/tests/js1_8_5/regress/regress-620376-1.js +++ b/js/src/tests/js1_8_5/regress/regress-620376-1.js @@ -10,7 +10,7 @@ function test() { if (typeof timeout != "function") return; - var p = Proxy.create({ enumerate: function() { return Array(1e9); }}); + var p = Proxy.create({ keys: function() { return Array(1e9); }}); expectExitCode(6); timeout(0.001); diff --git a/js/src/tests/js1_8_5/regress/regress-620376-2.js b/js/src/tests/js1_8_5/regress/regress-620376-2.js index acae97e36449..e886b6804b0b 100644 --- a/js/src/tests/js1_8_5/regress/regress-620376-2.js +++ b/js/src/tests/js1_8_5/regress/regress-620376-2.js @@ -5,7 +5,7 @@ */ function test() { - var p = Proxy.create({ enumerate: function() { return { get length() { throw 1; }}; }}); + var p = Proxy.create({ keys: function() { return { get length() { throw 1; }}; }}); try { for (i in p);