Ignore:
Timestamp:
Jun 30, 2021, 7:03:55 PM (4 years ago)
Author:
[email protected]
Message:

[JSC] Private names should be handled by usedVariables mechanism
https://bugs.webkit.org/show_bug.cgi?id=227476
rdar://76049469

Reviewed by Saam Barati.
Source/JavaScriptCore:

Private name handling in the current parser has many problems.

  1. The parser backtracks when it sees destructuring assignment, arrow function etc. In that case, the discarded code must not have any effect on the outside of that code. However, private name handling is annotating "used" of the upper scopes, which is wrong.
  2. In class expression, private name lookup intentionally skips the class-scope when parsing class heritage. But this is not correct since CodeBlock will perform lookup on the normal scope chain and this will look into the class-scope inconsistently. This means that we could encounter different private name at runtime. (it is tested in the added test).
  3. We skip inner function parsing when it is parsed previously. At that case, we must preserve private name annotation, but restored function information does not preserve that.

This patch changes how private name is handled.

  1. We were anyway defining #XXX variables which holds private symbols. So we track "use" information by the mechanism used for usual variables. We remove Used / Declared bits from PrivateNameEntry since they are not necessary at runtime, and these information is handled / tracked in Parser's Scope. For backtracking, we already have a mechanism to roll-back m_usedVariables, so using variable mechanism automatically fixes the problem.
  2. We define class-head-scope separately from class-scope. class-heritage expression can see class name, but it cannot use private names. Previously, our implementation attempted to achieve that by hacky way: skipping this class-scope for private names only while parsing class-heritage. But this was wrong since it does not consider CodeBlock's linking phase as described in the problem (2). Instead, we just define class-head-scope which holds class constructor name.
  3. We clean up popScopeInternal to populate lexical-variables and function-stack. Previously, we are stealing them before popping the scope when necessary, but this is a hack and a bit wrong since scope's popping operation needs to access these information in some cases. Instead, popScopeInternal populates them after popping the scope.
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::pushClassHeadLexicalScope):
(JSC::BytecodeGenerator::popClassHeadLexicalScope):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ClassExprNode::emitBytecode):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createClassExpr):
(JSC::ASTBuilder::createBlockStatement):
(JSC::ASTBuilder::createForLoop):
(JSC::ASTBuilder::createForInLoop):
(JSC::ASTBuilder::createForOfLoop):
(JSC::ASTBuilder::createTryStatement):
(JSC::ASTBuilder::createSwitchStatement):

  • parser/NodeConstructors.h:

(JSC::ForNode::ForNode):
(JSC::TryNode::TryNode):
(JSC::ClassExprNode::ClassExprNode):
(JSC::SwitchNode::SwitchNode):
(JSC::BlockNode::BlockNode):
(JSC::EnumerationNode::EnumerationNode):
(JSC::ForInNode::ForInNode):
(JSC::ForOfNode::ForOfNode):

  • parser/Nodes.cpp:

(JSC::ScopeNode::ScopeNode):
(JSC::ProgramNode::ProgramNode):
(JSC::ModuleProgramNode::ModuleProgramNode):
(JSC::EvalNode::EvalNode):
(JSC::FunctionNode::FunctionNode):
(JSC::VariableEnvironmentNode::VariableEnvironmentNode):

  • parser/Nodes.h:

(JSC::VariableEnvironmentNode::VariableEnvironmentNode): Deleted.

  • parser/Parser.cpp:

(JSC::isPrivateFieldName):
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseSwitchStatement):
(JSC::Parser<LexerType>::parseTryStatement):
(JSC::Parser<LexerType>::parseBlockStatement):
(JSC::Parser<LexerType>::parseFunctionDeclarationStatement):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseBinaryExpression):
(JSC::Parser<LexerType>::parseMemberExpression):
(JSC::Parser<LexerType>::usePrivateName): Deleted.

  • parser/Parser.h:

(JSC::Scope::finalizeLexicalEnvironment):
(JSC::Scope::takeLexicalEnvironment):
(JSC::Scope::takeDeclaredVariables):
(JSC::Scope::takeFunctionDeclarations):
(JSC::Scope::forEachUsedVariable):
(JSC::Scope::usePrivateName):
(JSC::Scope::currentUsedVariablesSize):
(JSC::Parser::popScopeInternal):
(JSC::Parser::popScope):
(JSC::Parser<LexerType>::parse):
(JSC::Scope::copyUndeclaredPrivateNamesTo): Deleted.
(JSC::Scope::hasUsedButUndeclaredPrivateNames const): Deleted.
(JSC::Parser::privateNameScope): Deleted.
(JSC::Parser::copyUndeclaredPrivateNamesToOuterScope): Deleted.

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createClassExpr):
(JSC::SyntaxChecker::createBlockStatement):
(JSC::SyntaxChecker::createForLoop):
(JSC::SyntaxChecker::createForInLoop):
(JSC::SyntaxChecker::createForOfLoop):
(JSC::SyntaxChecker::createTryStatement):
(JSC::SyntaxChecker::createSwitchStatement):

  • parser/VariableEnvironment.cpp:

(JSC::VariableEnvironmentEntry::dump const):
(JSC::VariableEnvironment::declarePrivateField):
(JSC::VariableEnvironment::declarePrivateAccessor):
(JSC::VariableEnvironment::declarePrivateMethod):
(JSC::VariableEnvironment::dump const):

  • parser/VariableEnvironment.h:

(JSC::VariableEnvironment::declarePrivateField):
(JSC::VariableEnvironment::privateNameEnvironment):
(JSC::VariableEnvironment::addPrivateNamesFrom):
(JSC::PrivateNameEntry::isUsed const): Deleted.
(JSC::PrivateNameEntry::isDeclared const): Deleted.
(JSC::PrivateNameEntry::setIsUsed): Deleted.
(JSC::PrivateNameEntry::setIsDeclared): Deleted.
(JSC::VariableEnvironment::usePrivateName): Deleted.
(JSC::VariableEnvironment::copyPrivateNamesTo const): Deleted.
(JSC::VariableEnvironment::copyUndeclaredPrivateNamesTo const): Deleted.

File:
1 edited

Legend:

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

    r278588 r279447  
    416416    }
    417417
    418     ClassExprNode* createClassExpr(const JSTokenLocation& location, const ParserClassInfo<ASTBuilder>& classInfo, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
     418    ClassExprNode* createClassExpr(const JSTokenLocation& location, const ParserClassInfo<ASTBuilder>& classInfo, VariableEnvironment&& classHeadEnvironment, VariableEnvironment&& classEnvironment, ExpressionNode* constructor,
    419419        ExpressionNode* parentClass, PropertyListNode* classElements, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
    420420    {
    421421        SourceCode source = m_sourceCode->subExpression(classInfo.startOffset, classInfo.endOffset, classInfo.startLine, classInfo.startColumn);
    422         ClassExprNode* node = new (m_parserArena) ClassExprNode(location, *classInfo.className, source, classEnvironment, constructor, parentClass, classElements);
     422        ClassExprNode* node = new (m_parserArena) ClassExprNode(location, *classInfo.className, source, WTFMove(classHeadEnvironment), WTFMove(classEnvironment), constructor, parentClass, classElements);
    423423        setExceptionLocation(node, start, divot, end);
    424424        return node;
     
    588588    }
    589589
    590     StatementNode* createBlockStatement(const JSTokenLocation& location, JSC::SourceElements* elements, int startLine, int endLine, VariableEnvironment& lexicalVariables, DeclarationStacks::FunctionStack&& functionStack)
    591     {
    592         BlockNode* block = new (m_parserArena) BlockNode(location, elements, lexicalVariables, WTFMove(functionStack));
     590    StatementNode* createBlockStatement(const JSTokenLocation& location, JSC::SourceElements* elements, int startLine, int endLine, VariableEnvironment&& lexicalVariables, DeclarationStacks::FunctionStack&& functionStack)
     591    {
     592        BlockNode* block = new (m_parserArena) BlockNode(location, elements, WTFMove(lexicalVariables), WTFMove(functionStack));
    593593        block->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
    594594        return block;
     
    609609    }
    610610
    611     StatementNode* createForLoop(const JSTokenLocation& location, ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, int start, int end, VariableEnvironment& lexicalVariables)
    612     {
    613         ForNode* result = new (m_parserArena) ForNode(location, initializer, condition, iter, statements, lexicalVariables);
     611    StatementNode* createForLoop(const JSTokenLocation& location, ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, int start, int end, VariableEnvironment&& lexicalVariables)
     612    {
     613        ForNode* result = new (m_parserArena) ForNode(location, initializer, condition, iter, statements, WTFMove(lexicalVariables));
    614614        result->setLoc(start, end, location.startOffset, location.lineStartOffset);
    615615        return result;
    616616    }
    617617
    618     StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation&, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
    619     {
    620         ForInNode* result = new (m_parserArena) ForInNode(location, lhs, iter, statements, lexicalVariables);
     618    StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation&, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment&& lexicalVariables)
     619    {
     620        ForInNode* result = new (m_parserArena) ForInNode(location, lhs, iter, statements, WTFMove(lexicalVariables));
    621621        result->setLoc(start, end, location.startOffset, location.lineStartOffset);
    622622        setExceptionLocation(result, eStart, eDivot, eEnd);
     
    624624    }
    625625   
    626     StatementNode* createForInLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation& declLocation, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
     626    StatementNode* createForInLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation& declLocation, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment&& lexicalVariables)
    627627    {
    628628        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(declLocation, pattern, nullptr);
    629         return createForInLoop(location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, lexicalVariables);
    630     }
    631    
    632     StatementNode* createForOfLoop(bool isForAwait, const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation&, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
    633     {
    634         ForOfNode* result = new (m_parserArena) ForOfNode(isForAwait, location, lhs, iter, statements, lexicalVariables);
     629        return createForInLoop(location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, WTFMove(lexicalVariables));
     630    }
     631   
     632    StatementNode* createForOfLoop(bool isForAwait, const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation&, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment&& lexicalVariables)
     633    {
     634        ForOfNode* result = new (m_parserArena) ForOfNode(isForAwait, location, lhs, iter, statements, WTFMove(lexicalVariables));
    635635        result->setLoc(start, end, location.startOffset, location.lineStartOffset);
    636636        setExceptionLocation(result, eStart, eDivot, eEnd);
     
    638638    }
    639639   
    640     StatementNode* createForOfLoop(bool isForAwait, const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation& declLocation, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
     640    StatementNode* createForOfLoop(bool isForAwait, const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTokenLocation& declLocation, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment&& lexicalVariables)
    641641    {
    642642        auto lexpr = new (m_parserArena) DestructuringAssignmentNode(declLocation, pattern, nullptr);
    643         return createForOfLoop(isForAwait, location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, lexicalVariables);
     643        return createForOfLoop(isForAwait, location, lexpr, iter, statements, declLocation, eStart, eDivot, eEnd, start, end, WTFMove(lexicalVariables));
    644644    }
    645645
     
    733733    }
    734734
    735     StatementNode* createTryStatement(const JSTokenLocation& location, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine, VariableEnvironment& catchEnvironment)
    736     {
    737         TryNode* result = new (m_parserArena) TryNode(location, tryBlock, catchPattern, catchBlock, catchEnvironment, finallyBlock);
     735    StatementNode* createTryStatement(const JSTokenLocation& location, StatementNode* tryBlock, DestructuringPatternNode* catchPattern, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine, VariableEnvironment&& catchEnvironment)
     736    {
     737        TryNode* result = new (m_parserArena) TryNode(location, tryBlock, catchPattern, catchBlock, WTFMove(catchEnvironment), finallyBlock);
    738738        result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
    739739        return result;
    740740    }
    741741
    742     StatementNode* createSwitchStatement(const JSTokenLocation& location, ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine, VariableEnvironment& lexicalVariables, DeclarationStacks::FunctionStack&& functionStack)
     742    StatementNode* createSwitchStatement(const JSTokenLocation& location, ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine, VariableEnvironment&& lexicalVariables, DeclarationStacks::FunctionStack&& functionStack)
    743743    {
    744744        CaseBlockNode* cases = new (m_parserArena) CaseBlockNode(firstClauses, defaultClause, secondClauses);
    745         SwitchNode* result = new (m_parserArena) SwitchNode(location, expr, cases, lexicalVariables, WTFMove(functionStack));
     745        SwitchNode* result = new (m_parserArena) SwitchNode(location, expr, cases, WTFMove(lexicalVariables), WTFMove(functionStack));
    746746        result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
    747747        return result;
Note: See TracChangeset for help on using the changeset viewer.