<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[244330] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/244330">244330</a></dd>
<dt>Author</dt> <dd>caitp@igalia.com</dd>
<dt>Date</dt> <dd>2019-04-16 08:58:59 -0700 (Tue, 16 Apr 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Filter DontEnum properties in ProxyObject::getOwnPropertyNames()
https://bugs.webkit.org/show_bug.cgi?id=176810

Reviewed by Saam Barati.

JSTests:

Add tests for the DontEnum filtering, and variations of other tests
take the DontEnum-filtering path.

* stress/proxy-own-keys.js:
(i.catch):
(set assert):
(set add):
(let.set new):
(get let):

Source/JavaScriptCore:

This adds conditional logic following the invariant checks, to perform
filtering in common uses of getOwnPropertyNames.

While this would ideally only be done in JSPropertyNameEnumerator, adding
the filtering to ProxyObject::performGetOwnPropertyNames maintains the
invariant that the EnumerationMode is properly followed.

This was originally rolled out in <a href="http://trac.webkit.org/projects/webkit/changeset/244020">r244020</a>, as DontEnum filtering code
in ObjectConstructor.cpp's ownPropertyKeys() had not been removed. It's
now redundant due to being handled in ProxyObject::getOwnPropertyNames().

* runtime/PropertyNameArray.h:
(JSC::PropertyNameArray::reset):
* runtime/ProxyObject.cpp:
(JSC::ProxyObject::performGetOwnPropertyNames):

Source/WebCore:

Previously, there was a comment here indicating uncertainty of whether it
was necessary to filter DontEnum properties explicitly or not. It turns
out that it was necessary in the case of JSC ProxyObjects.

This patch adds DontEnum filtering for ProxyObjects, however we continue
to explicitly filter them in JSDOMConvertRecord, which needs to use the
property descriptor after filtering. This change prevents observably
fetching the property descriptor twice per property.

* bindings/js/JSDOMConvertRecord.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestsstressproxyownkeysjs">trunk/JSTests/stress/proxy-own-keys.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeObjectConstructorcpp">trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimePropertyNameArrayh">trunk/Source/JavaScriptCore/runtime/PropertyNameArray.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeProxyObjectcpp">trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsjsJSDOMConvertRecordh">trunk/Source/WebCore/bindings/js/JSDOMConvertRecord.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/JSTests/ChangeLog     2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2019-04-16  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] Filter DontEnum properties in ProxyObject::getOwnPropertyNames()
+        https://bugs.webkit.org/show_bug.cgi?id=176810
+
+        Reviewed by Saam Barati.
+
+        Add tests for the DontEnum filtering, and variations of other tests
+        take the DontEnum-filtering path.
+
+        * stress/proxy-own-keys.js:
+        (i.catch):
+        (set assert):
+        (set add):
+        (let.set new):
+        (get let):
+
</ins><span class="cx"> 2019-04-15  Saam barati  <sbarati@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Modify how we do SetArgument when we inline varargs calls
</span></span></pre></div>
<a id="trunkJSTestsstressproxyownkeysjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/proxy-own-keys.js (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/proxy-own-keys.js   2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/JSTests/stress/proxy-own-keys.js      2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -135,6 +135,22 @@
</span><span class="cx">         assert(called);
</span><span class="cx">         called = false;
</span><span class="cx">     }
</span><ins>+
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        let foundKey = false;
+        try {
+            for (let k in proxy)
+                foundKey = true;
+        } catch(e) {
+            threw = true;
+            assert(e.toString() === "TypeError: Proxy object's non-extensible 'target' has configurable property 'x' that was not in the result from the 'ownKeys' trap");
+            assert(!foundKey);
+        }
+        assert(threw);
+        assert(called);
+        called = false;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> {
</span><span class="lines">@@ -166,6 +182,22 @@
</span><span class="cx">         assert(called);
</span><span class="cx">         called = false;
</span><span class="cx">     }
</span><ins>+
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        let reached = false;
+        try {
+            for (let k in proxy)
+                reached = true;
+        } catch (e) {
+            threw = true;
+            assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' method returned a key that was not present in its non-extensible target");
+        }
+        assert(threw);
+        assert(called);
+        assert(!reached);
+        called = false;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> {
</span><span class="lines">@@ -667,3 +699,68 @@
</span><span class="cx">         error = null;
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+{
+    let error = null;
+    let s1 = Symbol();
+    let s2 = Symbol();
+    let target = Object.defineProperties({}, {
+        x: {
+            value: "X",
+            enumerable: true,
+            configurable: true,
+        },
+        dontEnum1: {
+            value: "dont-enum",
+            enumerable: false,
+            configurable: true,
+        },
+        y: {
+            get() { return "Y"; },
+            enumerable: true,
+            configurable: true,
+        },
+        dontEnum2: {
+            get() { return "dont-enum-accessor" },
+            enumerable: false,
+            configurable: true
+        },
+        [s1]: {
+            value: "s1",
+            enumerable: true,
+            configurable: true,
+        },
+        [s2]: {
+            value: "dont-enum-symbol",
+            enumerable: false,
+            configurable: true,  
+        },
+    });
+    let checkedOwnKeys = false;
+    let checkedPropertyDescriptor = false;
+    let handler = {
+        ownKeys() {
+            checkedOwnKeys = true;
+            return ["x", "dontEnum1", "y", "dontEnum2", s1, s2];
+        },
+        getOwnPropertyDescriptor(t, k) {
+            checkedPropertyDescriptors = true;
+            return Reflect.getOwnPropertyDescriptor(t, k);
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        checkedPropertyDescriptors = false;
+        assert(shallowEq(["x", "dontEnum1", "y", "dontEnum2", s1, s2], Reflect.ownKeys(proxy)));
+        assert(checkedOwnKeys);
+        assert(!checkedPropertyDescriptors);
+        checkedOwnKeys = false;
+
+        let enumerableStringKeys = [];
+        for (let k in proxy)
+            enumerableStringKeys.push(k);
+        assert(shallowEq(["x", "y"], enumerableStringKeys));
+        assert(checkedOwnKeys);
+        assert(checkedPropertyDescriptors);
+    }
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/Source/JavaScriptCore/ChangeLog       2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2019-04-16  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] Filter DontEnum properties in ProxyObject::getOwnPropertyNames()
+        https://bugs.webkit.org/show_bug.cgi?id=176810
+
+        Reviewed by Saam Barati.
+
+        This adds conditional logic following the invariant checks, to perform
+        filtering in common uses of getOwnPropertyNames.
+
+        While this would ideally only be done in JSPropertyNameEnumerator, adding
+        the filtering to ProxyObject::performGetOwnPropertyNames maintains the
+        invariant that the EnumerationMode is properly followed.
+
+        This was originally rolled out in r244020, as DontEnum filtering code
+        in ObjectConstructor.cpp's ownPropertyKeys() had not been removed. It's
+        now redundant due to being handled in ProxyObject::getOwnPropertyNames().
+
+        * runtime/PropertyNameArray.h:
+        (JSC::PropertyNameArray::reset):
+        * runtime/ProxyObject.cpp:
+        (JSC::ProxyObject::performGetOwnPropertyNames):
+
</ins><span class="cx"> 2019-04-15  Saam barati  <sbarati@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Modify how we do SetArgument when we inline varargs calls
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeObjectConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp        2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp   2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -920,23 +920,9 @@
</span><span class="cx">     object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx"> 
</span><del>-    // https://tc39.github.io/ecma262/#sec-enumerableownproperties
-    // If {object} is a Proxy, an explicit and observable [[GetOwnProperty]] op is required to filter out non-enumerable properties.
-    // In other cases, filtering has already been performed.
-    const bool mustFilterProperty = dontEnumPropertiesMode == DontEnumPropertiesMode::Exclude && object->type() == ProxyObjectType;
-    auto filterPropertyIfNeeded = [exec, object, mustFilterProperty](const Identifier& identifier) {
-        if (!mustFilterProperty)
-            return true;
-        PropertyDescriptor descriptor;
-        PropertyName name(identifier);
-        return object->getOwnPropertyDescriptor(exec, name, descriptor) && descriptor.enumerable();
-    };
-
-    // If !mustFilterProperty and PropertyNameMode::Strings mode, we do not need to filter out any entries in PropertyNameArray.
-    // We can use fast allocation and initialization.
</del><span class="cx">     if (propertyNameMode != PropertyNameMode::StringsAndSymbols) {
</span><span class="cx">         ASSERT(propertyNameMode == PropertyNameMode::Strings || propertyNameMode == PropertyNameMode::Symbols);
</span><del>-        if (!mustFilterProperty && properties.size() < MIN_SPARSE_ARRAY_INDEX) {
</del><ins>+        if (properties.size() < MIN_SPARSE_ARRAY_INDEX) {
</ins><span class="cx">             if (LIKELY(!globalObject->isHavingABadTime())) {
</span><span class="cx">                 if (isObjectKeys) {
</span><span class="cx">                     Structure* structure = object->structure(vm);
</span><span class="lines">@@ -993,10 +979,7 @@
</span><span class="cx">         for (size_t i = 0; i < numProperties; i++) {
</span><span class="cx">             const auto& identifier = properties[i];
</span><span class="cx">             ASSERT(!identifier.isSymbol());
</span><del>-            bool hasProperty = filterPropertyIfNeeded(identifier);
-            EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
-            if (hasProperty)
-                pushDirect(exec, keys, jsOwnedString(exec, identifier.string()));
</del><ins>+            pushDirect(exec, keys, jsOwnedString(exec, identifier.string()));
</ins><span class="cx">             RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -1008,10 +991,7 @@
</span><span class="cx">             const auto& identifier = properties[i];
</span><span class="cx">             ASSERT(identifier.isSymbol());
</span><span class="cx">             ASSERT(!identifier.isPrivateName());
</span><del>-            bool hasProperty = filterPropertyIfNeeded(identifier);
-            EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
-            if (hasProperty)
-                pushDirect(exec, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
</del><ins>+            pushDirect(exec, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
</ins><span class="cx">             RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -1028,19 +1008,13 @@
</span><span class="cx">                 continue;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            bool hasProperty = filterPropertyIfNeeded(identifier);
-            EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
-            if (hasProperty)
-                pushDirect(exec, keys, jsOwnedString(exec, identifier.string()));
</del><ins>+            pushDirect(exec, keys, jsOwnedString(exec, identifier.string()));
</ins><span class="cx">             RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // To ensure the order defined in the spec (9.1.12), we append symbols at the last elements of keys.
</span><span class="cx">         for (const auto& identifier : propertySymbols) {
</span><del>-            bool hasProperty = filterPropertyIfNeeded(identifier);
-            EXCEPTION_ASSERT(!scope.exception() || !hasProperty);
-            if (hasProperty)
-                pushDirect(exec, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
</del><ins>+            pushDirect(exec, keys, Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl())));
</ins><span class="cx">             RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimePropertyNameArrayh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/PropertyNameArray.h (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/PropertyNameArray.h  2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/Source/JavaScriptCore/runtime/PropertyNameArray.h     2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -55,6 +55,12 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void reset()
+    {
+        m_set.clear();
+        m_data = PropertyNameArrayData::create();
+    }
+
</ins><span class="cx">     VM* vm() { return m_vm; }
</span><span class="cx"> 
</span><span class="cx">     void add(uint32_t index)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeProxyObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp      2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp 2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -1006,19 +1006,35 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (targetIsExensible)
-        return;
</del><ins>+    if (!targetIsExensible) {
+        for (UniquedStringImpl* impl : targetConfigurableKeys) {
+            if (removeIfContainedInUncheckedResultKeys(impl) == IsNotContainedIn) {
+                throwVMTypeError(exec, scope, makeString("Proxy object's non-extensible 'target' has configurable property '", String(impl), "' that was not in the result from the 'ownKeys' trap"));
+                return;
+            }
+        }
</ins><span class="cx"> 
</span><del>-    for (UniquedStringImpl* impl : targetConfigurableKeys) {
-        if (removeIfContainedInUncheckedResultKeys(impl) == IsNotContainedIn) {
-            throwVMTypeError(exec, scope, makeString("Proxy object's non-extensible 'target' has configurable property '", String(impl), "' that was not in the result from the 'ownKeys' trap"));
</del><ins>+        if (uncheckedResultKeys.size()) {
+            throwVMTypeError(exec, scope, "Proxy handler's 'ownKeys' method returned a key that was not present in its non-extensible target"_s);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (uncheckedResultKeys.size()) {
-        throwVMTypeError(exec, scope, "Proxy handler's 'ownKeys' method returned a key that was not present in its non-extensible target"_s);
-        return;
</del><ins>+    if (!enumerationMode.includeDontEnumProperties()) {
+        // Filtering DontEnum properties is observable in proxies and must occur following the invariant checks above.
+        auto data = trapResult.releaseData();
+        trapResult.reset();
+
+        for (auto propertyName : data->propertyNameVector()) {
+            PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+            auto result = getOwnPropertySlotCommon(exec, propertyName, slot);
+            RETURN_IF_EXCEPTION(scope, void());
+            if (!result)
+                continue;
+            if (slot.attributes() & PropertyAttribute::DontEnum)
+                continue;
+            trapResult.addUnchecked(propertyName.impl());
+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/Source/WebCore/ChangeLog      2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2019-04-16  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] Filter DontEnum properties in ProxyObject::getOwnPropertyNames()
+        https://bugs.webkit.org/show_bug.cgi?id=176810
+
+        Reviewed by Saam Barati.
+
+        Previously, there was a comment here indicating uncertainty of whether it
+        was necessary to filter DontEnum properties explicitly or not. It turns
+        out that it was necessary in the case of JSC ProxyObjects.
+
+        This patch adds DontEnum filtering for ProxyObjects, however we continue
+        to explicitly filter them in JSDOMConvertRecord, which needs to use the
+        property descriptor after filtering. This change prevents observably
+        fetching the property descriptor twice per property.
+
+        * bindings/js/JSDOMConvertRecord.h:
+
</ins><span class="cx"> 2019-04-15  Antoine Quint  <graouts@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [iOS] Redundant pointer events causes material design buttons to flush twice
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSDOMConvertRecordh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/JSDOMConvertRecord.h (244329 => 244330)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSDOMConvertRecord.h    2019-04-16 09:41:00 UTC (rev 244329)
+++ trunk/Source/WebCore/bindings/js/JSDOMConvertRecord.h       2019-04-16 15:58:59 UTC (rev 244330)
</span><span class="lines">@@ -86,7 +86,7 @@
</span><span class="cx">     
</span><span class="cx">         // 4. Let keys be ? O.[[OwnPropertyKeys]]().
</span><span class="cx">         JSC::PropertyNameArray keys(&vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
</span><del>-        object->methodTable(vm)->getOwnPropertyNames(object, &state, keys, JSC::EnumerationMode());
</del><ins>+        object->methodTable(vm)->getOwnPropertyNames(object, &state, keys, JSC::EnumerationMode(JSC::DontEnumPropertiesMode::Include));
</ins><span class="cx"> 
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, { });
</span><span class="cx"> 
</span><span class="lines">@@ -99,9 +99,8 @@
</span><span class="cx"> 
</span><span class="cx">             // 2. If desc is not undefined and desc.[[Enumerable]] is true:
</span><span class="cx"> 
</span><del>-            // FIXME: Do we need to check for enumerable / undefined, or is this handled by the default
-            // enumeration mode?
-
</del><ins>+            // It's necessary to filter enumerable here rather than using the default EnumerationMode,
+            // to prevent an observable extra [[GetOwnProperty]] operation in the case of ProxyObject records.
</ins><span class="cx">             if (didGetDescriptor && descriptor.enumerable()) {
</span><span class="cx">                 // 1. Let typedKey be key converted to an IDL value of type K.
</span><span class="cx">                 auto typedKey = Detail::IdentifierConverter<K>::convert(state, key);
</span></span></pre>
</div>
</div>

</body>
</html>