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/Parser.h

    r278588 r279447  
    2424
    2525#include "ExecutableInfo.h"
     26#include "IterationStatus.h"
    2627#include "Lexer.h"
    2728#include "ModuleScopeData.h"
     
    320321    VariableEnvironment& declaredVariables() { return m_declaredVariables; }
    321322    VariableEnvironment& lexicalVariables() { return m_lexicalVariables; }
    322     VariableEnvironment& finalizeLexicalEnvironment()
    323     { 
     323    void finalizeLexicalEnvironment()
     324    {
    324325        if (m_usesEval || m_needsFullActivation)
    325326            m_lexicalVariables.markAllVariablesAsCaptured();
    326327        else
    327328            computeLexicallyCapturedVariablesAndPurgeCandidates();
    328 
    329         return m_lexicalVariables;
    330     }
     329    }
     330
     331    VariableEnvironment takeLexicalEnvironment() { return WTFMove(m_lexicalVariables); }
     332    VariableEnvironment takeDeclaredVariables() { return WTFMove(m_declaredVariables); }
    331333
    332334    void computeLexicallyCapturedVariablesAndPurgeCandidates()
     
    422424        m_functionDeclarations.append(node);
    423425    }
    424     DeclarationStacks::FunctionStack&& takeFunctionDeclarations() { return WTFMove(m_functionDeclarations); }
     426    DeclarationStacks::FunctionStack takeFunctionDeclarations() { return WTFMove(m_functionDeclarations); }
    425427   
    426428
     
    479481    {
    480482        return m_lexicalVariables.hasPrivateName(ident);
    481     }
    482 
    483     void copyUndeclaredPrivateNamesTo(Scope& other)
    484     {
    485         m_lexicalVariables.copyUndeclaredPrivateNamesTo(other.m_lexicalVariables);
    486     }
    487 
    488     bool hasUsedButUndeclaredPrivateNames() const
    489     {
    490         if (m_lexicalVariables.privateNamesSize() > 0) {
    491             for (auto entry : m_lexicalVariables.privateNames()) {
    492                 if (entry.value.isUsed() && !entry.value.isDeclared())
    493                     return true;
    494             }
    495         }
    496         return false;
    497     }
    498 
    499     void usePrivateName(const Identifier& ident)
    500     {
    501         ASSERT(m_allowsLexicalDeclarations);
    502         m_lexicalVariables.usePrivateName(ident);
    503483    }
    504484
     
    612592    {
    613593        for (const UniquedStringImplPtrSet& set : m_usedVariables) {
    614             for (UniquedStringImpl* impl : set)
    615                 func(impl);
     594            for (UniquedStringImpl* impl : set) {
     595                if (func(impl) == IterationStatus::Done)
     596                    return;
     597            }
    616598        }
    617599    }
     
    625607        m_usedVariables.last().add(impl);
    626608    }
     609    void usePrivateName(const Identifier& ident)
     610    {
     611        ASSERT(m_allowsLexicalDeclarations);
     612        useVariable(&ident, false);
     613    }
    627614
    628615    void pushUsedVariableSet() { m_usedVariables.append(UniquedStringImplPtrSet()); }
    629616    size_t currentUsedVariablesSize() { return m_usedVariables.size(); }
    630 
    631617    void revertToPreviousUsedVariables(size_t size) { m_usedVariables.resize(size); }
    632618
     
    12811267    }
    12821268
    1283     ScopeRef privateNameScope()
    1284     {
    1285         ASSERT(m_scopeStack.size());
    1286         unsigned i = m_scopeStack.size() - 1;
    1287         while (i && !m_scopeStack[i].isPrivateNameScope())
    1288             i--;
    1289 
    1290         ASSERT(m_scopeStack[i].isPrivateNameScope());
    1291         return ScopeRef(&m_scopeStack, i);
    1292     }
    1293 
    1294     bool copyUndeclaredPrivateNamesToOuterScope()
    1295     {
    1296         ScopeRef current = privateNameScope();
    1297         unsigned i = current.index() - 1;
    1298         while (i && !m_scopeStack[i].isPrivateNameScope())
    1299             i--;
    1300 
    1301         if (!i)
    1302             return !current->hasUsedButUndeclaredPrivateNames();
    1303 
    1304         current->copyUndeclaredPrivateNamesTo(m_scopeStack[i]);
    1305         return true;
    1306     }
    1307 
    13081269    ScopeRef closestParentOrdinaryFunctionNonLexicalScope()
    13091270    {
     
    13431304    }
    13441305
    1345     void popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
     1306    std::tuple<VariableEnvironment, DeclarationStacks::FunctionStack> popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
    13461307    {
    13471308        EXCEPTION_ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
    13481309        ASSERT(m_scopeStack.size() > 1);
    1349         m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
     1310        Scope& lastScope = m_scopeStack.last();
     1311
     1312        // Finalize lexical variables.
     1313        lastScope.finalizeLexicalEnvironment();
     1314        m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&lastScope, shouldTrackClosedVariables);
    13501315       
    1351         if (m_scopeStack.last().isArrowFunction())
    1352             m_scopeStack.last().setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded();
     1316        if (lastScope.isArrowFunction())
     1317            lastScope.setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded();
    13531318       
    1354         if (!(m_scopeStack.last().isFunctionBoundary() && !m_scopeStack.last().isArrowFunctionBoundary()))
    1355             m_scopeStack[m_scopeStack.size() - 2].mergeInnerArrowFunctionFeatures(m_scopeStack.last().innerArrowFunctionFeatures());
    1356 
    1357         if (!m_scopeStack.last().isFunctionBoundary() && m_scopeStack.last().needsFullActivation())
     1319        if (!(lastScope.isFunctionBoundary() && !lastScope.isArrowFunctionBoundary()))
     1320            m_scopeStack[m_scopeStack.size() - 2].mergeInnerArrowFunctionFeatures(lastScope.innerArrowFunctionFeatures());
     1321
     1322        if (!lastScope.isFunctionBoundary() && lastScope.needsFullActivation())
    13581323            m_scopeStack[m_scopeStack.size() - 2].setNeedsFullActivation();
     1324        std::tuple result { lastScope.takeLexicalEnvironment(), lastScope.takeFunctionDeclarations() };
    13591325        m_scopeStack.removeLast();
    1360     }
    1361    
    1362     ALWAYS_INLINE void popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
    1363     {
    1364         popScopeInternal(scope, shouldTrackClosedVariables);
    1365     }
    1366    
    1367     ALWAYS_INLINE void popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
     1326        return result;
     1327    }
     1328   
     1329    ALWAYS_INLINE std::tuple<VariableEnvironment, DeclarationStacks::FunctionStack> popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
     1330    {
     1331        return popScopeInternal(scope, shouldTrackClosedVariables);
     1332    }
     1333   
     1334    ALWAYS_INLINE std::tuple<VariableEnvironment, DeclarationStacks::FunctionStack> popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
    13681335    {
    13691336        scope.setPopped();
    1370         popScopeInternal(scope, shouldTrackClosedVariables);
    1371     }
    1372 
    1373     ALWAYS_INLINE void popScope(AutoCleanupLexicalScope& cleanupScope, bool shouldTrackClosedVariables)
     1337        return popScopeInternal(scope, shouldTrackClosedVariables);
     1338    }
     1339
     1340    ALWAYS_INLINE std::tuple<VariableEnvironment, DeclarationStacks::FunctionStack> popScope(AutoCleanupLexicalScope& cleanupScope, bool shouldTrackClosedVariables)
    13741341    {
    13751342        RELEASE_ASSERT(cleanupScope.isValid());
    13761343        ScopeRef& scope = cleanupScope.scope();
    13771344        cleanupScope.setPopped();
    1378         popScopeInternal(scope, shouldTrackClosedVariables);
     1345        return popScopeInternal(scope, shouldTrackClosedVariables);
    13791346    }
    13801347
     
    15101477        DeclarationStacks::FunctionStack functionDeclarations;
    15111478        VariableEnvironment varDeclarations;
     1479        VariableEnvironment lexicalVariables;
    15121480        UniquedStringImplPtrSet sloppyModeHoistedFunctions;
    15131481        CodeFeatures features;
     
    18401808    template <class TreeBuilder> ALWAYS_INLINE bool isSimpleAssignmentTarget(TreeBuilder&, TreeExpression);
    18411809
    1842     ALWAYS_INLINE bool usePrivateName(const Identifier*);
    1843 
    18441810    ALWAYS_INLINE int isBinaryOperator(JSTokenType);
    18451811    bool allowAutomaticSemicolon();
     
    21242090    DebuggerParseData* m_debuggerParseData;
    21252091    CallOrApplyDepthScope* m_callOrApplyDepthScope { nullptr };
    2126     bool m_seenTaggedTemplate { false };
    21272092    bool m_isInsideOrdinaryFunction;
     2093    bool m_seenTaggedTemplateInNonReparsingFunctionMode { false };
     2094    bool m_seenPrivateNameUseInNonReparsingFunctionMode { false };
    21282095};
    21292096
     
    21732140                                    endColumn,
    21742141                                    parseResult.value().sourceElements,
    2175                                     parseResult.value().varDeclarations,
     2142                                    WTFMove(parseResult.value().varDeclarations),
    21762143                                    WTFMove(parseResult.value().functionDeclarations),
    2177                                     currentScope()->finalizeLexicalEnvironment(),
     2144                                    WTFMove(parseResult.value().lexicalVariables),
    21782145                                    WTFMove(parseResult.value().sloppyModeHoistedFunctions),
    21792146                                    parseResult.value().parameters,
Note: See TracChangeset for help on using the changeset viewer.