Ignore:
Timestamp:
Mar 9, 2015, 4:47:06 PM (10 years ago)
Author:
[email protected]
Message:

Support extends and super keywords
https://bugs.webkit.org/show_bug.cgi?id=142200

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Added the support for ES6 class syntax inheritance.

Added ConstructorKind as well as boolean flags indicating the constructor kind to
various classes in UnlinkedCodeBlock as well as AST nodes.

Each method stores the associated class as its homeObjectPrivateName. This value is used to
make super calls.

  • bytecode/UnlinkedCodeBlock.cpp:

(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):

  • bytecode/UnlinkedCodeBlock.h:

(JSC::ExecutableInfo::ExecutableInfo):
(JSC::UnlinkedFunctionExecutable::constructorKindIsDerived): Added.
(JSC::UnlinkedCodeBlock::constructorKindIsDerived): Added.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator): Don't emit op_create_this in a derived class
as the object is allocated by the highest base class's constructor. Also set "this" to null
and store the original value in m_newTargetRegister. "this" is supposed to be in TDZ but
that will be implemented in a separate patch.
(JSC::BytecodeGenerator::emitReturn): Allow "undefined" to be returned from a derived class.
In a derived class's constructor, not returning "undefined" or an object results in a type
error instead of "this" being returned.
(JSC::BytecodeGenerator::emitThrowTypeError): Added.

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::constructorKindIsDerived): Added.
(JSC::BytecodeGenerator::newTarget): Added.

  • bytecompiler/NodesCodegen.cpp:

(JSC::SuperNode::emitBytecode): Added. Emits the code to obtain the callee's parent class.
(JSC::emitSuperBaseForCallee): Added. Emits the code to obtain the parent class's prototype.
(JSC::emitPutHomeObject): Added.
(JSC::PropertyListNode::emitBytecode): Stores the home object when adding methods.
(JSC::PropertyListNode::emitPutConstantProperty): Ditto.
(JSC::BracketAccessorNode::emitBytecode): Added the support for superfoo.
(JSC::DotAccessorNode::emitBytecode): Added the support for super.foo.
(JSC::FunctionCallValueNode::emitBytecode): Added the support for super().
(JSC::FunctionCallBracketNode::emitBytecode): Added the support for superfoo().
(JSC::FunctionCallDotNode::emitBytecode): Added the support for super.foo().
(JSC::DeleteBracketNode::emitBytecode): Forbid "delete super.foo".
(JSC::DeleteDotNode::emitBytecode): Forbid "delete superfoo".
(JSC::ClassExprNode::emitBytecode): Added the support for "classHeritage". This is the main
logic for inheritance. When a class B inherits from a class A, set B.proto to A and set
B.prototype.proto to A.prototype. Throw exceptions when either A or A.proto is not
an object.

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::superExpr): Added.

  • parser/NodeConstructors.h:

(JSC::SuperNode::SuperNode): Added.

  • parser/Nodes.cpp:

(JSC::FunctionBodyNode::FunctionBodyNode):

  • parser/Nodes.h:

(JSC::ExpressionNode::isSuperNode):
(JSC::PropertyNode::type):
(JSC::PropertyNode::needsSuperBinding):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseFunctionBody):
(JSC::Parser<LexerType>::parseFunctionInfo): Throw a parser error if super() is used outside
of class constructors.
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass): ConstructorKind is "derived" if and only if the parent
class is specified in the declaration / expression.
(JSC::Parser<LexerType>::parseGetterSetter):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseMemberExpression): Added the support for "super()", "super.foo",
and "superfoo". Throw a semantic error if "super" appears by itself.

  • parser/Parser.h:

(JSC::Scope::Scope): Added m_hasDirectSuper. This variable keeps track of the use of "super()"
so that parseFunctionInfo can spit an error if it's used outside of class constructors.
(JSC::Scope::hasDirectSuper): Added.
(JSC::Scope::setHasDirectSuper): Added.

  • parser/ParserModes.h:

(JSC::ConstructorKind): Added.

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::superExpr): Added.

  • runtime/CommonIdentifiers.h: Added homeObjectPrivateName.
  • runtime/Executable.h:

(JSC::EvalExecutable::executableInfo):
(JSC::ProgramExecutable::executableInfo):

LayoutTests:

Added tests for "extends" and "super" keywords.

  • TestExpectations:
  • js/class-syntax-extends-expected.txt: Added.
  • js/class-syntax-extends.html: Added.
  • js/class-syntax-super-expected.txt: Added.
  • js/class-syntax-super.html: Added.
  • js/script-tests/class-syntax-extends.js: Added.
  • js/script-tests/class-syntax-super.js: Added.
File:
1 edited

Legend:

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

    r181183 r181293  
    12561256
    12571257template <typename LexerType>
    1258 template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(TreeBuilder& context)
     1258template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(TreeBuilder& context, ConstructorKind constructorKind)
    12591259{
    12601260    JSTokenLocation startLocation(tokenLocation());
     
    12641264    if (match(CLOSEBRACE)) {
    12651265        unsigned endColumn = tokenColumn();
    1266         return context.createFunctionBody(startLocation, tokenLocation(), startColumn, endColumn, strictMode());
     1266        return context.createFunctionBody(startLocation, tokenLocation(), startColumn, endColumn, strictMode(), constructorKind);
    12671267    }
    12681268    DepthManager statementDepth(&m_statementDepth);
     
    12711271    failIfFalse(parseSourceElements(bodyBuilder, CheckForStrictMode), "Cannot parse body of this function");
    12721272    unsigned endColumn = tokenColumn();
    1273     return context.createFunctionBody(startLocation, tokenLocation(), startColumn, endColumn, strictMode());
     1273    return context.createFunctionBody(startLocation, tokenLocation(), startColumn, endColumn, strictMode(), constructorKind);
    12741274}
    12751275
     
    12911291
    12921292template <typename LexerType>
    1293 template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, FunctionParseMode mode, bool nameIsInContainingScope, ParserFunctionInfo<TreeBuilder>& info)
     1293template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, FunctionParseMode mode,
     1294    bool nameIsInContainingScope, ConstructorKind constructorKind, ParserFunctionInfo<TreeBuilder>& info)
    12941295{
    12951296    AutoPopScopeRef functionScope(this, pushScope());
     
    13441345        unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
    13451346
    1346         info.body = context.createFunctionBody(startLocation, endLocation, info.bodyStartColumn, bodyEndColumn, cachedInfo->strictMode);
     1347        info.body = context.createFunctionBody(startLocation, endLocation, info.bodyStartColumn, bodyEndColumn, cachedInfo->strictMode, constructorKind);
    13471348       
    13481349        functionScope->restoreFromSourceProviderCache(cachedInfo);
     
    13671368    m_lastFunctionName = lastFunctionName;
    13681369    ParserState oldState = saveState();
    1369     info.body = parseFunctionBody(context);
     1370    info.body = parseFunctionBody(context, constructorKind);
    13701371    restoreState(oldState);
    13711372    failIfFalse(info.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
    13721373    context.setEndOffset(info.body, m_lexer->currentOffset());
    13731374    if (functionScope->strictMode() && info.name) {
    1374         RELEASE_ASSERT(mode == FunctionMode);
     1375        RELEASE_ASSERT(mode == FunctionMode || mode == MethodMode);
    13751376        semanticFailIfTrue(m_vm->propertyNames->arguments == *info.name, "'", info.name->impl(), "' is not a valid function name in strict mode");
    13761377        semanticFailIfTrue(m_vm->propertyNames->eval == *info.name, "'", info.name->impl(), "' is not a valid function name in strict mode");
     1378    }
     1379    if (functionScope->hasDirectSuper()) {
     1380        bool nameIsConstructor = info.name && *info.name == m_vm->propertyNames->constructor;
     1381        semanticFailIfTrue(mode != MethodMode || !nameIsConstructor, "Cannot call super() outside of a class constructor");
    13771382    }
    13781383    info.closeBraceOffset = m_token.m_data.offset;
     
    14161421    next();
    14171422    ParserFunctionInfo<TreeBuilder> info;
    1418     failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, info)), "Cannot parse this function");
     1423    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, ConstructorKind::Base, info)), "Cannot parse this function");
    14191424    failIfFalse(info.name, "Function statements must have a name");
    14201425    failIfFalseIfStrict(declareVariable(info.name), "Cannot declare a function named '", info.name->impl(), "' in strict mode");
     
    14661471        parentClass = parsePrimaryExpression(context);
    14671472        failIfFalse(parentClass, "Cannot parse the parent class name");
    1468         failWithMessage("Inheritance is not supported yet");
    1469     }
     1473    }
     1474    const ConstructorKind constructorKind = parentClass ? ConstructorKind::Derived : ConstructorKind::Base;
    14701475
    14711476    consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings, "Expected opening '{' at the start of a class body");
     
    14991504            semanticFailIfTrue(isStaticMethod, "Cannot declare a static", stringForFunctionMode(isGetter ? GetterMode : SetterMode));
    15001505            nextExpectIdentifier(LexerFlagsIgnoreReservedWords);
    1501             property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter, methodStart);
     1506            property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter, methodStart, SuperBinding::Needed);
    15021507            failIfFalse(property, "Cannot parse this method");
    15031508        } else {
    15041509            ParserFunctionInfo<TreeBuilder> methodInfo;
    1505             failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, false, methodInfo)), "Cannot parse this method");
     1510            failIfFalse((parseFunctionInfo(context, FunctionNeedsName, MethodMode, false, constructorKind, methodInfo)), "Cannot parse this method");
    15061511            failIfFalse(methodInfo.name, "method must have a name");
    15071512            failIfFalse(declareVariable(methodInfo.name), "Cannot declare a method named '", methodInfo.name->impl(), "'");
     
    15211526            semanticFailIfTrue(isStaticMethod && *methodInfo.name == propertyNames.prototype,
    15221527                "Cannot declare a static method named 'prototype'");
    1523             property = context.createProperty(methodInfo.name, method, PropertyNode::Constant, PropertyNode::Unknown, alwaysStrictInsideClass);
     1528            property = context.createProperty(methodInfo.name, method, PropertyNode::Constant, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed);
    15241529        }
    15251530
     
    20082013    unsigned methodStart = tokenStart();
    20092014    ParserFunctionInfo<TreeBuilder> methodInfo;
    2010     failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, methodInfo)), "Cannot parse this method");
     2015    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, ConstructorKind::Base, methodInfo)), "Cannot parse this method");
    20112016    methodInfo.name = methodName;
    20122017    return context.createFunctionExpr(methodLocation, methodInfo, methodStart);
     
    20142019
    20152020template <typename LexerType>
    2016 template <class TreeBuilder> TreeProperty Parser<LexerType>::parseGetterSetter(TreeBuilder& context, bool strict, PropertyNode::Type type, unsigned getterOrSetterStartOffset)
     2021template <class TreeBuilder> TreeProperty Parser<LexerType>::parseGetterSetter(TreeBuilder& context, bool strict, PropertyNode::Type type, unsigned getterOrSetterStartOffset, SuperBinding superBinding)
    20172022{
    20182023    const Identifier* stringPropertyName = 0;
     
    20292034    if (type == PropertyNode::Getter) {
    20302035        failIfFalse(match(OPENPAREN), "Expected a parameter list for getter definition");
    2031         failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, GetterMode, false, info)), "Cannot parse getter definition");
     2036        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, GetterMode, false, ConstructorKind::Base, info)), "Cannot parse getter definition");
    20322037    } else {
    20332038        failIfFalse(match(OPENPAREN), "Expected a parameter list for setter definition");
    2034         failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SetterMode, false, info)), "Cannot parse setter definition");
     2039        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SetterMode, false, ConstructorKind::Base, info)), "Cannot parse setter definition");
    20352040    }
    20362041    if (stringPropertyName)
    2037         return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, getterOrSetterStartOffset);
    2038     return context.createGetterOrSetterProperty(const_cast<VM*>(m_vm), m_parserArena, location, type, strict, numericPropertyName, info, getterOrSetterStartOffset);
     2042        return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, getterOrSetterStartOffset, superBinding);
     2043    return context.createGetterOrSetterProperty(const_cast<VM*>(m_vm), m_parserArena, location, type, strict, numericPropertyName, info, getterOrSetterStartOffset, superBinding);
    20392044}
    20402045
     
    22212226        ParserFunctionInfo<TreeBuilder> info;
    22222227        info.name = &m_vm->propertyNames->nullIdentifier;
    2223         failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, info)), "Cannot parse function expression");
     2228        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, ConstructorKind::Base, info)), "Cannot parse function expression");
    22242229        return context.createFunctionExpr(location, info, functionKeywordStart);
    22252230    }
     
    23712376    }
    23722377
    2373     base = parsePrimaryExpression(context);
    2374    
     2378#if ENABLE(ES6_CLASS_SYNTAX)
     2379    bool baseIsSuper = match(SUPER);
     2380#else
     2381    bool baseIsSuper = false;
     2382#endif
     2383
     2384    if (baseIsSuper) {
     2385        base = context.superExpr(location);
     2386        next();
     2387    } else
     2388        base = parsePrimaryExpression(context);
     2389
    23752390    failIfFalse(base, "Cannot parse base expression");
    23762391    while (true) {
     
    24032418                TreeArguments arguments = parseArguments(context, AllowSpread);
    24042419                failIfFalse(arguments, "Cannot parse call arguments");
     2420                if (baseIsSuper)
     2421                    currentScope()->setHasDirectSuper();
    24052422                base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
    24062423            }
     
    24202437            goto endMemberExpression;
    24212438        }
     2439        baseIsSuper = false;
    24222440    }
    24232441endMemberExpression:
     2442    semanticFailIfTrue(baseIsSuper && !newCount, "Cannot reference super");
    24242443    while (newCount--)
    24252444        base = context.createNewExpr(location, base, expressionStart, lastTokenEndPosition());
Note: See TracChangeset for help on using the changeset viewer.