⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 243933 in webkit


Ignore:
Timestamp:
Apr 5, 2019, 6:45:08 AM (7 years ago)
Author:
caitp@igalia.com
Message:

JSTests:
[JSC] throw if 'ownKeys' Proxy trap result contains duplicate keys
https://bugs.webkit.org/show_bug.cgi?id=185211

Reviewed by Saam Barati.

This is for the normative spec change in https://github.com/tc39/ecma262/pull/833

This changes several assertions to expect a TypeError to be thrown (in some cases,
changing thee expected message).

  • es6/Proxy_ownKeys_duplicates.js:

(handler):
(shouldThrow):
(test):

  • stress/Object_static_methods_Object.getOwnPropertyDescriptors-proxy.js:

(shouldThrow):

  • stress/proxy-own-keys.js:

(i.catch):
(assert):

LayoutTests/imported/w3c:
[JSC] throw if 'ownKeys' Proxy trap result contains duplicate keys
https://bugs.webkit.org/show_bug.cgi?id=185211

Reviewed by Saam Barati.

This is for the normative spec change in https://github.com/tc39/ecma262/pull/833

Change some test expectations which were previously expected to fail.

  • web-platform-tests/fetch/api/headers/headers-record-expected.txt:

Source/JavaScriptCore:
[JSC] throw if ownKeys Proxy trap result contains duplicate keys
https://bugs.webkit.org/show_bug.cgi?id=185211

Reviewed by Saam Barati.

Implements the normative spec change in https://github.com/tc39/ecma262/pull/833

This involves tracking duplicate keys returned from the ownKeys trap in yet
another HashTable, and may incur a minor performance penalty in some cases. This
is not expected to significantly affect web performance.

  • runtime/ProxyObject.cpp:

(JSC::ProxyObject::performGetOwnPropertyNames):

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r243925 r243933  
     12019-04-05  Caitlin Potter  <caitp@igalia.com>
     2
     3        [JSC] throw if 'ownKeys' Proxy trap result contains duplicate keys
     4        https://bugs.webkit.org/show_bug.cgi?id=185211
     5
     6        Reviewed by Saam Barati.
     7
     8        This is for the normative spec change in https://github.com/tc39/ecma262/pull/833
     9
     10        This changes several assertions to expect a TypeError to be thrown (in some cases,
     11        changing thee expected message).
     12
     13        * es6/Proxy_ownKeys_duplicates.js:
     14        (handler):
     15        (shouldThrow):
     16        (test):
     17        * stress/Object_static_methods_Object.getOwnPropertyDescriptors-proxy.js:
     18        (shouldThrow):
     19        * stress/proxy-own-keys.js:
     20        (i.catch):
     21        (assert):
     22
    1232019-04-04  Yusuke Suzuki  <ysuzuki@apple.com>
    224
  • trunk/JSTests/es6/Proxy_ownKeys_duplicates.js

    r215799 r243933  
     1function handler(key) {
     2    return {
     3        getOwnPropertyDescriptor(t, n) {
     4            // Required to prevent Object.keys() from discarding results
     5            return {
     6                enumerable: true,
     7                configurable: true,
     8            };
     9        },
     10        ownKeys(t) {
     11            return [key, key];
     12        }
     13    };
     14}
     15
     16function shouldThrow(op, errorConstructor, desc) {
     17    try {
     18        op();
     19    } catch (e) {
     20        if (!(e instanceof errorConstructor)) {
     21            throw new Error(`threw ${e}, but should have thrown ${errorConstructor.name}`);
     22        }
     23        return;
     24    }
     25    throw new Error(`Expected ${desc || 'operation'} to throw ${errorConstructor.name}, but no exception thrown`);
     26}
     27
    128function test() {
    229
    330var symbol = Symbol("test");
    4 var proxy = new Proxy({}, {
    5     getOwnPropertyDescriptor(t, n) {
    6         // Required to prevent Object.keys() from discarding results
    7         return {
    8             enumerable: true,
    9             configurable: true
    10         };
    11     },
    12     ownKeys: function (t) {
    13         return ["A", "A", "0", "0", symbol, symbol];
    14     }
    15 });
    16 var keys = Object.keys(proxy);
    17 var names = Object.getOwnPropertyNames(proxy);
    18 var symbols = Object.getOwnPropertySymbols(proxy);
     31var proxyNamed = new Proxy({}, handler("A"));
     32var proxyIndexed = new Proxy({}, handler(0));
     33var proxySymbol = new Proxy({}, handler(symbol));
    1934
    20 if (keys.length === 4 && keys[0] === keys[1] && keys[2] === keys[3] &&
    21     keys[0] === "A" && keys[2] === "0" &&
    22     names.length === 4 && names[0] === names[1] && names[2] === names[3] &&
    23     names[0] === "A" && names[2] === "0" &&
    24     symbols.length === 2 && symbols[0] === symbols[1] && symbols[0] === symbol)
    25     return true;
    26 return false;
     35shouldThrow(() => Object.keys(proxyNamed), TypeError, "Object.keys with duplicate named properties");
     36shouldThrow(() => Object.keys(proxyIndexed), TypeError, "Object.keys with duplicate indexed properties");
     37shouldThrow(() => Object.keys(proxySymbol), TypeError, "Object.keys with duplicate symbol properties");
     38
     39shouldThrow(() => Object.getOwnPropertyNames(proxyNamed), TypeError, "Object.getOwnPropertyNames with duplicate named properties");
     40shouldThrow(() => Object.getOwnPropertyNames(proxyIndexed), TypeError, "Object.getOwnPropertyNames with duplicate indexed properties");
     41shouldThrow(() => Object.getOwnPropertyNames(proxySymbol), TypeError, "Object.getOwnPropertyNames with duplicate symbol properties");
     42
     43shouldThrow(() => Object.getOwnPropertySymbols(proxyNamed), TypeError, "Object.getOwnPropertySymbols with duplicate named properties");
     44shouldThrow(() => Object.getOwnPropertySymbols(proxyIndexed), TypeError, "Object.getOwnPropertySymbols with duplicate indexed properties");
     45shouldThrow(() => Object.getOwnPropertySymbols(proxySymbol), TypeError, "Object.getOwnPropertySymbols with duplicate symbol properties");
     46
     47return true;
    2748
    2849}
  • trunk/JSTests/stress/Object_static_methods_Object.getOwnPropertyDescriptors-proxy.js

    r203747 r243933  
    1717    shouldBe(undefined, expected.get, name + '.get');
    1818    shouldBe(undefined, expected.set, name + '.set');
     19}
     20
     21function shouldThrow(op, errorConstructor, desc) {
     22    try {
     23        op();
     24        throw new Error(`Expected ${desc || 'operation'} to throw ${errorConstructor.name}, but no exception thrown`);
     25    } catch (e) {
     26        if (!(e instanceof errorConstructor)) {
     27            throw new Error(`threw ${e}, but should have thrown ${errorConstructor.name}`);
     28        }
     29    }
    1930}
    2031
     
    8192  });
    8293
    83   var result = Object.getOwnPropertyDescriptors(P);
    84   shouldBe(true, result.A.configurable, 'for result.A.configurable');
    85   shouldBe(false, result.A.writable, 'for result.A.writable');
    86   shouldBe('VALUE', result.A.value, 'for result.A.value');
    87   shouldBe(false, result.A.enumerable, 'for result.A.enumerable');
    88   shouldBe(true, Object.hasOwnProperty.call(result, 'A'));
    89   shouldBe('ownKeys()|getOwnPropertyDescriptor(A)|getOwnPropertyDescriptor(A)', log.join('|'));
     94  shouldThrow(() => Object.getOwnPropertyDescriptors(P), TypeError, 'ownKeys returning duplicates');
     95  shouldBe('ownKeys()', log.join('|'));
    9096})();
    9197
  • trunk/JSTests/stress/proxy-own-keys.js

    r215799 r243933  
    188188
    189189    for (let i = 0; i < 500; i++) {
    190         // FIXME: we may update the spec to make this test not throw.
    191         // see: https://github.com/tc39/ecma262/pull/594
     190        // Throws per https://github.com/tc39/ecma262/pull/833
    192191        let threw = false;
    193192        try {
    194193            Reflect.ownKeys(p2);
    195194        } catch(e) {
    196             assert(e.toString() === "TypeError: Proxy object's 'target' has the non-configurable property 'a' that was not in the result from the 'ownKeys' trap");
     195            assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' trap result must not contain any duplicate names");
    197196            threw = true;
    198197        }
     
    223222
    224223    for (let i = 0; i < 500; i++) {
    225         // FIXME: we may update the spec to make this test not throw.
    226         // see: https://github.com/tc39/ecma262/pull/594
     224        // Throws per https://github.com/tc39/ecma262/pull/833
    227225        let threw = false;
    228226        try {
    229227            Reflect.ownKeys(p2);
    230228        } catch(e) {
    231             assert(e.toString() === "TypeError: Proxy object's non-extensible 'target' has configurable property 'a' that was not in the result from the 'ownKeys' trap");
     229            assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' trap result must not contain any duplicate names");
    232230            threw = true;
    233231        }
     
    256254    let proxy = new Proxy(target, handler);
    257255    for (let i = 0; i < 500; i++) {
    258         Object.keys(proxy);
    259         assert(called);
    260         called = false;
     256        try {
     257            Object.keys(proxy);
     258        } catch(e) {
     259            assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' trap result must not contain any duplicate names");
     260            threw = true;
     261        }
     262        assert(called);
     263        assert(threw);
     264        called = false;
     265        threw = false;
    261266    }
    262267}
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r243910 r243933  
     12019-04-05  Caitlin Potter  <caitp@igalia.com>
     2
     3        [JSC] throw if 'ownKeys' Proxy trap result contains duplicate keys
     4        https://bugs.webkit.org/show_bug.cgi?id=185211
     5
     6        Reviewed by Saam Barati.
     7
     8        This is for the normative spec change in https://github.com/tc39/ecma262/pull/833
     9
     10        Change some test expectations which were previously expected to fail.
     11
     12        * web-platform-tests/fetch/api/headers/headers-record-expected.txt:
     13
    1142019-04-04  Commit Queue  <commit-queue@webkit.org>
    215
  • trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/headers/headers-record-expected.txt

    r222307 r243933  
    1010PASS Correct operation ordering with non-enumerable properties
    1111PASS Correct operation ordering with undefined descriptors
    12 FAIL Correct operation ordering with repeated keys assert_throws: function "function () { var h = new Headers(proxy); }" did not throw
     12PASS Correct operation ordering with repeated keys
    1313FAIL Basic operation with Symbol keys assert_throws: function "function () { var h = new Headers(proxy); }" did not throw
    1414FAIL Operation with non-enumerable Symbol keys assert_equals: expected 9 but got 8
  • trunk/Source/JavaScriptCore/ChangeLog

    r243925 r243933  
     12019-04-05  Caitlin Potter  <caitp@igalia.com>
     2
     3        [JSC] throw if ownKeys Proxy trap result contains duplicate keys
     4        https://bugs.webkit.org/show_bug.cgi?id=185211
     5
     6        Reviewed by Saam Barati.
     7
     8        Implements the normative spec change in https://github.com/tc39/ecma262/pull/833
     9
     10        This involves tracking duplicate keys returned from the ownKeys trap in yet
     11        another HashTable, and may incur a minor performance penalty in some cases. This
     12        is not expected to significantly affect web performance.
     13
     14        * runtime/ProxyObject.cpp:
     15        (JSC::ProxyObject::performGetOwnPropertyNames):
     16
    1172019-04-04  Yusuke Suzuki  <ysuzuki@apple.com>
    218
  • trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp

    r238163 r243933  
    940940    RuntimeTypeMask dontThrowAnExceptionTypeFilter = TypeString | TypeSymbol;
    941941    HashSet<UniquedStringImpl*> uncheckedResultKeys;
     942    HashSet<UniquedStringImpl*> seenKeys;
    942943
    943944    auto addPropName = [&] (JSValue value, RuntimeType type) -> bool {
     
    945946        static const bool dontExitEarly = false;
    946947
     948        Identifier ident = value.toPropertyKey(exec);
     949        RETURN_IF_EXCEPTION(scope, doExitEarly);
     950
     951        // If trapResult contains any duplicate entries, throw a TypeError exception.
     952        //   
     953        // Per spec[1], filtering by type should occur _after_ [[OwnPropertyKeys]], so duplicates
     954        // are tracked in a separate hashtable from uncheckedResultKeys (which only contain the
     955        // keys filtered by type).
     956        //
     957        // [1] Per https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeysmust not contain any duplicate names"_s);
     958        if (!seenKeys.add(ident.impl()).isNewEntry) {
     959            throwTypeError(exec, scope, "Proxy handler's 'ownKeys' trap result must not contain any duplicate names"_s);
     960            return doExitEarly;
     961        }
     962
    947963        if (!(type & resultFilter))
    948964            return dontExitEarly;
    949 
    950         Identifier ident = value.toPropertyKey(exec);
    951         RETURN_IF_EXCEPTION(scope, doExitEarly);
    952965
    953966        uncheckedResultKeys.add(ident.impl());
Note: See TracChangeset for help on using the changeset viewer.