Ignore:
Timestamp:
Aug 25, 2020, 8:58:40 AM (5 years ago)
Author:
Alexey Shvayka
Message:

Invalid early error for object literal method named "proto"
https://bugs.webkit.org/show_bug.cgi?id=215760

Reviewed by Ross Kirsling.

JSTests:

  • test262/expectations.yaml: Mark 2 test cases as passing.

Source/JavaScriptCore:

According to Annex B [1], { __proto__: null, __proto__() {} } is a valid object literal as the second
__proto__ wasn't obtained from PropertyDefinition : PropertyName : AssignmentExpression production.
Currently, JSC throws an early SyntaxError, unlike V8 and SpiderMonkey.

Since a method needs super binding, the most straightforward fix would be adding SuperBinding field
to SyntaxChecker::Property and exposing it via an accessor. However, given that Property is a very
common structure, this approach would noticeably increase memory pressure during parsing.

Instead, this patch reworks SyntaxChecker::Property to accept isUnderscoreProtoSetter parameter,
removing optional name field, its accessor, and shouldCheckPropertyForUnderscoreProtoDuplicate(),
which reduces sizeof(SyntaxChecker::Property) by a factor of 8: from 16 to 2 bytes.
Also, this change avoids two extra makeNumericIdentifier() calls, speeding up numeric keys parsing.

This approach is feasible because "proto" is the only identifier-based early error for object
literals [2], with no such errors being added in upcoming stage 2-4 proposals.

Additionally, this patch removes strict / complete bool parameter from {parse,create}Property()
signatures as a) it was always true, b) is now unused, and c) strict mode can be checked via scope.

[1]: https://tc39.es/ecma262/#sec-__proto__-property-names-in-object-initializers
[2]: https://tc39.es/ecma262/#sec-object-initializer-static-semantics-early-errors

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createGetterOrSetterProperty):
(JSC::ASTBuilder::createProperty):
(JSC::ASTBuilder::isUnderscoreProtoSetter const):
(JSC::ASTBuilder::getName const): Deleted.

  • parser/Nodes.h:
  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parseObjectLiteral):
(JSC::Parser<LexerType>::shouldCheckPropertyForUnderscoreProtoDuplicate): Deleted.

  • parser/Parser.h:
  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::SyntaxChecker):
(JSC::SyntaxChecker::Property::Property):
(JSC::SyntaxChecker::Property::operator!):
(JSC::SyntaxChecker::createProperty):
(JSC::SyntaxChecker::createGetterOrSetterProperty):
(JSC::SyntaxChecker::operatorStackPop):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r262613 r266117  
    6565    };
    6666   
    67     SyntaxChecker(VM& , void*)
     67    SyntaxChecker(VM& vm, void*)
     68        : m_vm(vm)
    6869    {
    6970    }
     
    100101    struct Property {
    101102        ALWAYS_INLINE Property(void* = nullptr)
    102             : type((PropertyNode::Type)0)
    103         {
    104         }
    105         ALWAYS_INLINE Property(const Identifier* ident, PropertyNode::Type ty)
    106             : name(ident)
    107             , type(ty)
    108         {
    109         }
    110         ALWAYS_INLINE Property(PropertyNode::Type ty)
    111             : name(nullptr)
    112             , type(ty)
     103        {
     104        }
     105        ALWAYS_INLINE Property(PropertyNode::Type type)
     106            : type(type)
     107        {
     108        }
     109        ALWAYS_INLINE Property(PropertyNode::Type type, bool isUnderscoreProtoSetter)
     110            : type(type)
     111            , isUnderscoreProtoSetter(isUnderscoreProtoSetter)
    113112        {
    114113        }
    115114        ALWAYS_INLINE bool operator!() { return !type; }
    116         const Identifier* name;
    117         PropertyNode::Type type;
     115        PropertyNode::Type type { static_cast<PropertyNode::Type>(0) };
     116        bool isUnderscoreProtoSetter { false };
    118117    };
    119118    typedef int PropertyList;
     
    216215    int createArgumentsList(const JSTokenLocation&, int) { return ArgumentsListResult; }
    217216    int createArgumentsList(const JSTokenLocation&, int, int) { return ArgumentsListResult; }
    218     Property createProperty(const Identifier* name, int, PropertyNode::Type type, PropertyNode::PutType, bool complete, SuperBinding, InferName, ClassElementTag)
    219     {
    220         if (!complete)
    221             return Property(type);
    222         ASSERT(name);
    223         return Property(name, type);
    224     }
    225     Property createProperty(int, PropertyNode::Type type, PropertyNode::PutType, bool, SuperBinding, ClassElementTag)
    226     {
    227         return Property(type);
    228     }
    229     Property createProperty(VM& vm, ParserArena& parserArena, double name, int, PropertyNode::Type type, PropertyNode::PutType, bool complete, SuperBinding, ClassElementTag)
    230     {
    231         if (!complete)
    232             return Property(type);
    233         return Property(&parserArena.identifierArena().makeNumericIdentifier(vm, name), type);
    234     }
    235     Property createProperty(int, int, PropertyNode::Type type, PropertyNode::PutType, bool, SuperBinding, ClassElementTag)
    236     {
    237         return Property(type);
    238     }
    239     Property createProperty(const Identifier*, int, int, PropertyNode::Type type, PropertyNode::PutType, bool, SuperBinding, ClassElementTag)
     217    Property createProperty(const Identifier* name, int, PropertyNode::Type type, PropertyNode::PutType, SuperBinding superBinding, InferName, ClassElementTag)
     218    {
     219        return Property(type, PropertyNode::isUnderscoreProtoSetter(m_vm, name, type, superBinding == SuperBinding::Needed));
     220    }
     221    Property createProperty(int, PropertyNode::Type type, PropertyNode::PutType, SuperBinding, ClassElementTag)
     222    {
     223        return Property(type);
     224    }
     225    Property createProperty(VM&, ParserArena&, double, int, PropertyNode::Type type, PropertyNode::PutType, SuperBinding, ClassElementTag)
     226    {
     227        return Property(type);
     228    }
     229    Property createProperty(int, int, PropertyNode::Type type, PropertyNode::PutType, SuperBinding, ClassElementTag)
     230    {
     231        return Property(type);
     232    }
     233    Property createProperty(const Identifier*, int, int, PropertyNode::Type type, PropertyNode::PutType, SuperBinding, ClassElementTag)
    240234    {
    241235        return Property(type);
     
    292286
    293287    int appendConstDecl(const JSTokenLocation&, int, const Identifier*, int) { return StatementResult; }
    294     Property createGetterOrSetterProperty(const JSTokenLocation&, PropertyNode::Type type, bool strict, const Identifier* name, const ParserFunctionInfo<SyntaxChecker>&, ClassElementTag)
    295     {
    296         ASSERT(name);
    297         if (!strict)
    298             return Property(type);
    299         return Property(name, type);
    300     }
    301     Property createGetterOrSetterProperty(const JSTokenLocation&, PropertyNode::Type type, bool, int, const ParserFunctionInfo<SyntaxChecker>&, ClassElementTag)
    302     {
    303         return Property(type);
    304     }
    305     Property createGetterOrSetterProperty(VM& vm, ParserArena& parserArena, const JSTokenLocation&, PropertyNode::Type type, bool strict, double name, const ParserFunctionInfo<SyntaxChecker>&, ClassElementTag)
    306     {
    307         if (!strict)
    308             return Property(type);
    309         return Property(&parserArena.identifierArena().makeNumericIdentifier(vm, name), type);
     288    Property createGetterOrSetterProperty(const JSTokenLocation&, PropertyNode::Type type, const Identifier*, const ParserFunctionInfo<SyntaxChecker>&, ClassElementTag)
     289    {
     290        return Property(type);
     291    }
     292    Property createGetterOrSetterProperty(const JSTokenLocation&, PropertyNode::Type type, int, const ParserFunctionInfo<SyntaxChecker>&, ClassElementTag)
     293    {
     294        return Property(type);
     295    }
     296    Property createGetterOrSetterProperty(VM&, ParserArena&, const JSTokenLocation&, PropertyNode::Type type, double, const ParserFunctionInfo<SyntaxChecker>&, ClassElementTag)
     297    {
     298        return Property(type);
    310299    }
    311300
     
    340329    void assignmentStackAppend(int& assignmentStackDepth, int, int, int, int, Operator) { assignmentStackDepth = 1; }
    341330    int createAssignment(const JSTokenLocation&, int& assignmentStackDepth, int, int, int, int) { assignmentStackDepth = 0; return AssignmentExpr; }
    342     const Identifier* getName(const Property& property) const { return property.name; }
    343331    PropertyNode::Type getType(const Property& property) const { return property.type; }
     332    bool isUnderscoreProtoSetter(const Property& property) const { return property.isUnderscoreProtoSetter; }
    344333    bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
    345334    ExpressionType createDestructuringAssignment(const JSTokenLocation&, int, ExpressionType)
     
    448437
    449438private:
     439    VM& m_vm;
    450440    int m_topBinaryExpr;
    451441    int m_topUnaryToken;
Note: See TracChangeset for help on using the changeset viewer.