Changeset 191030 in webkit


Ignore:
Timestamp:
Oct 13, 2015, 8:56:53 PM (10 years ago)
Author:
Yusuke Suzuki
Message:

[ES6] Class expression should have lexical environment that has itself as an imutable binding
https://bugs.webkit.org/show_bug.cgi?id=150089

Reviewed by Geoffrey Garen.

According to ES6 spec, class expression has its own lexical environment that holds itself
as an immutable binding[1] (section 14.5.14 step 2, 3, 4, 23)

As a result, even if the binding declared in the outer scope is overridden, methods inside
class expression can refer its class by the class name.

[1]: http://ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-classdefinitionevaluation

  • bytecompiler/NodesCodegen.cpp:

(JSC::ClassExprNode::emitBytecode):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createClassExpr):

  • parser/NodeConstructors.h:

(JSC::ClassExprNode::ClassExprNode):

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

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

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createClassExpr):

  • tests/es6.yaml:
  • tests/stress/class-expression-generates-environment.js: Added.

(shouldBe):
(shouldThrow):
(prototype.method):
(staticMethod):
(A.prototype.method):
(A.staticMethod):
(A):

  • tests/stress/class-expression-should-be-tdz-in-heritage.js: Added.

(shouldThrow):
(shouldThrow.A):

Location:
trunk/Source/JavaScriptCore
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r191016 r191030  
     12015-10-13  Yusuke Suzuki  <[email protected]>
     2
     3        [ES6] Class expression should have lexical environment that has itself as an imutable binding
     4        https://bugs.webkit.org/show_bug.cgi?id=150089
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        According to ES6 spec, class expression has its own lexical environment that holds itself
     9        as an immutable binding[1] (section 14.5.14 step 2, 3, 4, 23)
     10
     11        As a result, even if the binding declared in the outer scope is overridden, methods inside
     12        class expression can refer its class by the class name.
     13
     14        [1]: http://ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-classdefinitionevaluation
     15
     16        * bytecompiler/NodesCodegen.cpp:
     17        (JSC::ClassExprNode::emitBytecode):
     18        * parser/ASTBuilder.h:
     19        (JSC::ASTBuilder::createClassExpr):
     20        * parser/NodeConstructors.h:
     21        (JSC::ClassExprNode::ClassExprNode):
     22        * parser/Nodes.h:
     23        * parser/Parser.cpp:
     24        (JSC::Parser<LexerType>::parseClass):
     25        * parser/SyntaxChecker.h:
     26        (JSC::SyntaxChecker::createClassExpr):
     27        * tests/es6.yaml:
     28        * tests/stress/class-expression-generates-environment.js: Added.
     29        (shouldBe):
     30        (shouldThrow):
     31        (prototype.method):
     32        (staticMethod):
     33        (A.prototype.method):
     34        (A.staticMethod):
     35        (A):
     36        * tests/stress/class-expression-should-be-tdz-in-heritage.js: Added.
     37        (shouldThrow):
     38        (shouldThrow.A):
     39
    1402015-10-13  Saam barati  <[email protected]>
    241
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r190847 r191030  
    30113011RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    30123012{
     3013    if (!m_name.isNull())
     3014        generator.pushLexicalScope(this, true);
     3015
    30133016    RefPtr<RegisterID> superclass;
    30143017    if (m_classHeritage) {
     
    30743077    if (m_instanceMethods)
    30753078        generator.emitNode(prototype.get(), m_instanceMethods);
     3079
     3080    if (!m_name.isNull()) {
     3081        Variable classNameVar = generator.variable(m_name);
     3082        RELEASE_ASSERT(classNameVar.isResolved());
     3083        RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar);
     3084        generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, Initialization);
     3085        generator.popLexicalScope(this);
     3086    }
    30763087
    30773088    return generator.moveToDestinationIfNeeded(dst, constructor.get());
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r190066 r191030  
    343343
    344344#if ENABLE(ES6_CLASS_SYNTAX)
    345     ClassExprNode* createClassExpr(const JSTokenLocation& location, const Identifier& name, ExpressionNode* constructor,
     345    ClassExprNode* createClassExpr(const JSTokenLocation& location, const Identifier& name, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
    346346        ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
    347347    {
    348         return new (m_parserArena) ClassExprNode(location, name, constructor, parentClass, instanceMethods, staticMethods);
     348        return new (m_parserArena) ClassExprNode(location, name, classEnvironment, constructor, parentClass, instanceMethods, staticMethods);
    349349    }
    350350#endif
  • trunk/Source/JavaScriptCore/parser/NodeConstructors.h

    r190014 r191030  
    923923    }
    924924
    925     inline ClassExprNode::ClassExprNode(const JSTokenLocation& location, const Identifier& name, ExpressionNode* constructorExpression, ExpressionNode* classHeritage, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
    926         : ExpressionNode(location)
     925    inline ClassExprNode::ClassExprNode(const JSTokenLocation& location, const Identifier& name, VariableEnvironment& classEnvironment, ExpressionNode* constructorExpression, ExpressionNode* classHeritage, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
     926        : ExpressionNode(location)
     927        , VariableEnvironmentNode(classEnvironment)
    927928        , m_name(name)
    928929        , m_constructorExpression(constructorExpression)
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r190014 r191030  
    19311931
    19321932#if ENABLE(ES6_CLASS_SYNTAX)
    1933     class ClassExprNode final : public ExpressionNode {
    1934     public:
    1935         ClassExprNode(const JSTokenLocation&, const Identifier&, ExpressionNode* constructorExpresssion,
     1933    class ClassExprNode final : public ExpressionNode, public VariableEnvironmentNode {
     1934    public:
     1935        using ParserArenaDeletable::operator new;
     1936
     1937        ClassExprNode(const JSTokenLocation&, const Identifier&, VariableEnvironment& classEnvironment, ExpressionNode* constructorExpresssion,
    19361938            ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods);
    19371939
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r190188 r191030  
    19241924
    19251925    AutoPopScopeRef classScope(this, pushScope());
     1926    classScope->setIsLexicalScope();
     1927    classScope->preventVarDeclarations();
    19261928    classScope->setStrictMode();
    19271929
     
    19311933        info.className = className;
    19321934        next();
    1933         failIfTrue(classScope->declareVariable(className) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
     1935        failIfTrue(classScope->declareLexicalVariable(className, true) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
    19341936    } else if (requirements == FunctionNeedsName) {
    19351937        if (match(OPENBRACE))
     
    20482050    }
    20492051
     2052    consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
     2053
     2054    auto classExpression = context.createClassExpr(location, *className, classScope->finalizeLexicalEnvironment(), constructor, parentClass, instanceMethods, staticMethods);
    20502055    popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
    2051     consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
    2052 
    2053     return context.createClassExpr(location, *className, constructor, parentClass, instanceMethods, staticMethods);
     2056    return classExpression;
    20542057}
    20552058#endif
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r189504 r191030  
    184184    ExpressionType createEmptyLetExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
    185185#if ENABLE(ES6_CLASS_SYNTAX)
    186     ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
     186    ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
    187187#endif
    188188    ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
  • trunk/Source/JavaScriptCore/tests/es6.yaml

    r190699 r191030  
    8787- path: es6/class_class_expression.js
    8888  cmd: runES6 :normal
     89- path: es6/class_class_name_is_lexically_scoped.js
     90  cmd: runES6 :normal
    8991- path: es6/class_class_statement.js
    9092  cmd: runES6 :normal
     
    729731- path: es6/block-level_function_declaration.js
    730732  cmd: runES6 :fail
    731 - path: es6/class_class_name_is_lexically_scoped.js
    732   cmd: runES6 :fail
    733733- path: es6/destructuring_computed_properties.js
    734734  cmd: runES6 :fail
Note: See TracChangeset for help on using the changeset viewer.