Ignore:
Timestamp:
Mar 14, 2018, 1:00:21 PM (7 years ago)
Author:
[email protected]
Message:

[JSC] fix order of evaluation for ClassDefinitionEvaluation
https://bugs.webkit.org/show_bug.cgi?id=183523

Reviewed by Keith Miller.

Computed property names need to be evaluated in source order during class
definition evaluation, as it's observable (and specified to work this way).

This change improves compatibility with Chromium.

JSTests:

  • stress/class_elements.js: Added.

(test):
(test.C.prototype.effect):
(test.C.effect):
(test.C.prototype.get effect):
(test.C.prototype.set effect):
(test.C):

Source/JavaScriptCore:

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::emitDefineClassElements):

  • bytecompiler/NodesCodegen.cpp:

(JSC::PropertyListNode::emitBytecode):
(JSC::ClassExprNode::emitBytecode):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createClassExpr):
(JSC::ASTBuilder::createGetterOrSetterProperty):
(JSC::ASTBuilder::createProperty):

  • parser/NodeConstructors.h:

(JSC::PropertyNode::PropertyNode):
(JSC::ClassExprNode::ClassExprNode):

  • parser/Nodes.cpp:

(JSC::PropertyListNode::hasStaticallyNamedProperty):

  • parser/Nodes.h:

(JSC::PropertyNode::isClassProperty const):
(JSC::PropertyNode::isStaticClassProperty const):
(JSC::PropertyNode::isInstanceClassProperty const):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parseGetterSetter):

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

(JSC::SyntaxChecker::createClassExpr):
(JSC::SyntaxChecker::createProperty):
(JSC::SyntaxChecker::createGetterOrSetterProperty):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r229162 r229608  
    27962796
    27972797    TreeExpression constructor = 0;
    2798     TreePropertyList staticMethods = 0;
    2799     TreePropertyList instanceMethods = 0;
    2800     TreePropertyList instanceMethodsTail = 0;
    2801     TreePropertyList staticMethodsTail = 0;
     2798    TreePropertyList classElements = 0;
     2799    TreePropertyList classElementsTail = 0;
    28022800    while (!match(CLOSEBRACE)) {
    28032801        if (match(SEMICOLON)) {
     
    28102808
    28112809        // For backwards compatibility, "static" is a non-reserved keyword in non-strict mode.
    2812         bool isStaticMethod = false;
     2810        ClassElementTag tag = ClassElementTag::Instance;
    28132811        if (match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm->propertyNames->staticKeyword) {
    28142812            SavePoint savePoint = createSavePoint();
     
    28182816                restoreSavePoint(savePoint);
    28192817            } else
    2820                 isStaticMethod = true;
     2818                tag = ClassElementTag::Static;
    28212819        }
    28222820
     
    28842882        const bool alwaysStrictInsideClass = true;
    28852883        if (isGetter || isSetter) {
    2886             bool isClassProperty = true;
    28872884            property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter,
    2888                 methodStart, ConstructorKind::None, isClassProperty, isStaticMethod);
     2885                methodStart, ConstructorKind::None, tag);
    28892886            failIfFalse(property, "Cannot parse this method");
    28902887        } else {
    28912888            ParserFunctionInfo<TreeBuilder> methodInfo;
    2892             bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
     2889            bool isConstructor = tag == ClassElementTag::Instance && *ident == propertyNames.constructor;
    28932890            if (isAsyncMethodParseMode(parseMode) || isAsyncGeneratorMethodParseMode(parseMode) || isGeneratorMethodParseMode(parseMode)) {
    28942891                isConstructor = false;
     
    29082905
    29092906            // FIXME: Syntax error when super() is called
    2910             semanticFailIfTrue(isStaticMethod && methodInfo.name && *methodInfo.name == propertyNames.prototype,
     2907            semanticFailIfTrue(tag == ClassElementTag::Static && methodInfo.name && *methodInfo.name == propertyNames.prototype,
    29112908                "Cannot declare a static method named 'prototype'");
    29122909
    2913             bool isClassProperty = true;
    29142910            if (computedPropertyName) {
    29152911                property = context.createProperty(computedPropertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed),
    2916                     PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, isClassProperty);
     2912                    PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, tag);
    29172913            } else {
    29182914                property = context.createProperty(methodInfo.name, method, PropertyNode::Constant,
    2919                     PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, InferName::Allowed, isClassProperty);
     2915                    PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, InferName::Allowed, tag);
    29202916            }
    29212917        }
    29222918
    2923         TreePropertyList& tail = isStaticMethod ? staticMethodsTail : instanceMethodsTail;
    2924         if (tail)
    2925             tail = context.createPropertyList(methodLocation, property, tail);
    2926         else {
    2927             tail = context.createPropertyList(methodLocation, property);
    2928             if (isStaticMethod)
    2929                 staticMethods = tail;
    2930             else
    2931                 instanceMethods = tail;
    2932         }
     2919        if (classElementsTail)
     2920            classElementsTail = context.createPropertyList(methodLocation, property, classElementsTail);
     2921        else
     2922            classElements = classElementsTail = context.createPropertyList(methodLocation, property);
    29332923    }
    29342924
     
    29362926    consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
    29372927
    2938     auto classExpression = context.createClassExpr(location, info, classScope->finalizeLexicalEnvironment(), constructor, parentClass, instanceMethods, staticMethods);
     2928    auto classExpression = context.createClassExpr(location, info, classScope->finalizeLexicalEnvironment(), constructor, parentClass, classElements);
    29392929    popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
    29402930    return classExpression;
     
    38993889    SourceParseMode parseMode = SourceParseMode::MethodMode;
    39003890    bool wasIdent = false;
    3901     bool isClassProperty = false;
    3902     bool isStaticMethod = false;
    39033891
    39043892    if (consume(TIMES))
     
    39493937            context.setEndOffset(node, m_lexer->currentOffset());
    39503938            InferName inferName = ident && *ident == m_vm->propertyNames->underscoreProto ? InferName::Disallowed : InferName::Allowed;
    3951             return context.createProperty(ident, node, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::NotNeeded, inferName, isClassProperty);
     3939            return context.createProperty(ident, node, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::NotNeeded, inferName, ClassElementTag::No);
    39523940        }
    39533941
     
    39553943            auto method = parsePropertyMethod(context, ident, parseMode);
    39563944            propagateError();
    3957             return context.createProperty(ident, method, PropertyNode::Constant, PropertyNode::KnownDirect, complete, SuperBinding::Needed, InferName::Allowed, isClassProperty);
     3945            return context.createProperty(ident, method, PropertyNode::Constant, PropertyNode::KnownDirect, complete, SuperBinding::Needed, InferName::Allowed, ClassElementTag::No);
    39583946        }
    39593947        failIfTrue(parseMode != SourceParseMode::MethodMode, "Expected a parenthesis for argument list");
     
    39693957                currentScope()->setInnerArrowFunctionUsesEval();
    39703958            TreeExpression node = context.createResolve(location, *ident, start, lastTokenEndPosition());
    3971             return context.createProperty(ident, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Shorthand), PropertyNode::KnownDirect, complete, SuperBinding::NotNeeded, InferName::Allowed, isClassProperty);
     3959            return context.createProperty(ident, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Shorthand), PropertyNode::KnownDirect, complete, SuperBinding::NotNeeded, InferName::Allowed, ClassElementTag::No);
    39723960        }
    39733961
     
    39823970        else
    39833971            failWithMessage("Expected a ':' following the property name '", ident->impl(), "'");
    3984         return parseGetterSetter(context, complete, type, getterOrSetterStartOffset, ConstructorKind::None, isClassProperty, isStaticMethod);
     3972        return parseGetterSetter(context, complete, type, getterOrSetterStartOffset, ConstructorKind::None, ClassElementTag::No);
    39853973    }
    39863974    case DOUBLE:
     
    39933981            auto method = parsePropertyMethod(context, &ident, parseMode);
    39943982            propagateError();
    3995             return context.createProperty(&ident, method, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::Needed, InferName::Allowed, isClassProperty);
     3983            return context.createProperty(&ident, method, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::Needed, InferName::Allowed, ClassElementTag::No);
    39963984        }
    39973985        failIfTrue(parseMode != SourceParseMode::MethodMode, "Expected a parenthesis for argument list");
     
    40013989        failIfFalse(node, "Cannot parse expression for property declaration");
    40023990        context.setEndOffset(node, m_lexer->currentOffset());
    4003         return context.createProperty(const_cast<VM*>(m_vm), m_parserArena, propertyName, node, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::NotNeeded, isClassProperty);
     3991        return context.createProperty(const_cast<VM*>(m_vm), m_parserArena, propertyName, node, PropertyNode::Constant, PropertyNode::Unknown, complete, SuperBinding::NotNeeded, ClassElementTag::No);
    40043992    }
    40053993    case OPENBRACKET: {
     
    40124000            auto method = parsePropertyMethod(context, &m_vm->propertyNames->nullIdentifier, parseMode);
    40134001            propagateError();
    4014             return context.createProperty(propertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::KnownDirect, complete, SuperBinding::Needed, isClassProperty);
     4002            return context.createProperty(propertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::KnownDirect, complete, SuperBinding::Needed, ClassElementTag::No);
    40154003        }
    40164004        failIfTrue(parseMode != SourceParseMode::MethodMode, "Expected a parenthesis for argument list");
     
    40204008        failIfFalse(node, "Cannot parse expression for property declaration");
    40214009        context.setEndOffset(node, m_lexer->currentOffset());
    4022         return context.createProperty(propertyName, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::Unknown, complete, SuperBinding::NotNeeded, isClassProperty);
     4010        return context.createProperty(propertyName, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::Unknown, complete, SuperBinding::NotNeeded, ClassElementTag::No);
    40234011    }
    40244012    case DOTDOTDOT: {
     
    40314019            failIfFalse(elem, "Cannot parse subject of a spread operation");
    40324020            auto node = context.createObjectSpreadExpression(spreadLocation, elem, start, divot, m_lastTokenEndPosition);
    4033             return context.createProperty(node, PropertyNode::Spread, PropertyNode::Unknown, complete, SuperBinding::NotNeeded, isClassProperty);
     4021            return context.createProperty(node, PropertyNode::Spread, PropertyNode::Unknown, complete, SuperBinding::NotNeeded, ClassElementTag::No);
    40344022        }
    40354023        FALLTHROUGH;
     
    40564044template <typename LexerType>
    40574045template <class TreeBuilder> TreeProperty Parser<LexerType>::parseGetterSetter(TreeBuilder& context, bool strict, PropertyNode::Type type, unsigned getterOrSetterStartOffset,
    4058     ConstructorKind constructorKind, bool isClassProperty, bool isStaticMethod)
     4046    ConstructorKind constructorKind, ClassElementTag tag)
    40594047{
    40604048    const Identifier* stringPropertyName = 0;
     
    40664054    if (matchSpecIdentifier() || match(STRING) || m_token.m_type & KeywordTokenFlag) {
    40674055        stringPropertyName = m_token.m_data.ident;
    4068         semanticFailIfTrue(isClassProperty && isStaticMethod && *stringPropertyName == m_vm->propertyNames->prototype,
     4056        semanticFailIfTrue(tag == ClassElementTag::Static && *stringPropertyName == m_vm->propertyNames->prototype,
    40694057            "Cannot declare a static method named 'prototype'");
    4070         semanticFailIfTrue(isClassProperty && !isStaticMethod && *stringPropertyName == m_vm->propertyNames->constructor,
     4058        semanticFailIfTrue(tag == ClassElementTag::Instance && *stringPropertyName == m_vm->propertyNames->constructor,
    40714059            "Cannot declare a getter or setter named 'constructor'");
    40724060        next();
     
    40924080
    40934081    if (stringPropertyName)
    4094         return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, isClassProperty);
     4082        return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, tag);
    40954083
    40964084    if (computedPropertyName)
    4097         return context.createGetterOrSetterProperty(location, static_cast<PropertyNode::Type>(type | PropertyNode::Computed), strict, computedPropertyName, info, isClassProperty);
    4098 
    4099     return context.createGetterOrSetterProperty(const_cast<VM*>(m_vm), m_parserArena, location, type, strict, numericPropertyName, info, isClassProperty);
     4085        return context.createGetterOrSetterProperty(location, static_cast<PropertyNode::Type>(type | PropertyNode::Computed), strict, computedPropertyName, info, tag);
     4086
     4087    return context.createGetterOrSetterProperty(const_cast<VM*>(m_vm), m_parserArena, location, type, strict, numericPropertyName, info, tag);
    41004088}
    41014089
Note: See TracChangeset for help on using the changeset viewer.