Ignore:
Timestamp:
Feb 6, 2022, 4:34:45 AM (3 years ago)
Author:
[email protected]
Message:

Object literal doesn't properly resolve name clash between an accessor and a constant property
https://bugs.webkit.org/show_bug.cgi?id=220574

Patch by Alexey Shvayka <[email protected]> on 2022-02-06
Reviewed by Yusuke Suzuki.

JSTests:

  • stress/class-static-accessor-name-clash-with-field.js: Added.
  • stress/object-literal-accessor-name-clash-with-constant.js: Added.

Source/JavaScriptCore:

The spec [1] calls DefineOwnProperty for every property node, whether it's a
getter, a setter, or a value. JSC attempts to reduce emitted bytecodes by setting
up a getter and a setter at once.

However, there is a slower path that exactly matches the spec, which was called only
if a spread syntax or a computed property was encountered. With this patch, the slower
path is also taken in case of a constant property (including a shorthand) with the
same name as an accessor.

That causes an incomplete accessor descriptor to correctly overwrite the existing
data one, which aligns JSC with V8 and SpiderMonkey.

This bug doesn't exist for static class fields and accessors because initialization
of class fields is deferred [2] and they always overwrite eponymous static methods /
accessors, no matter the order in source code. No reproduction for private elements either.

[1]: https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation (step 11 of "get", step 10 of "set")
[2]: https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation (step 31.a)

  • bytecompiler/NodesCodegen.cpp:

(JSC::PropertyListNode::emitBytecode):

LayoutTests:

Adjusted test now passes on V8 and SpiderMonkey as well.

  • js/class-syntax-method-names-expected.txt:
  • js/script-tests/class-syntax-method-names.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r288541 r289166  
    662662    if (p) {
    663663        // Build a list of getter/setter pairs to try to put them at the same time. If we encounter
    664         // a computed property or a spread, just emit everything as that may override previous values.
     664        // a constant property by the same name as accessor or a computed property or a spread,
     665        // just emit everything as that may override previous values.
    665666        bool canOverrideProperties = false;
    666667
     
    676677            }
    677678
    678             if (node->m_type & PropertyNode::Constant)
     679            GetterSetterMap& map = node->isStaticClassProperty() ? staticMap : instanceMap;
     680            if (node->m_type & PropertyNode::Constant) {
     681                if (map.contains(node->name()->impl())) {
     682                    canOverrideProperties = true;
     683                    break;
     684                }
    679685                continue;
     686            }
    680687
    681688            // Duplicates are possible.
    682689            GetterSetterPair pair(node, static_cast<PropertyNode*>(nullptr));
    683             GetterSetterMap& map = node->isStaticClassProperty() ? staticMap : instanceMap;
    684690            GetterSetterMap::AddResult result = map.add(node->name()->impl(), pair);
    685691            auto& resultPair = result.iterator->value;
Note: See TracChangeset for help on using the changeset viewer.