Ignore:
Timestamp:
Mar 9, 2012, 4:06:48 AM (13 years ago)
Author:
[email protected]
Message:

Refactor code feature analysis in the parser
https://bugs.webkit.org/show_bug.cgi?id=79112

Reviewed by Geoffrey Garen.

This commit refactors the parser to more uniformly propagate flag
bits down and up the parse process, as the parser descends and
returns into nested blocks. Some flags get passed town to
subscopes, some apply to specific scopes only, and some get
unioned up after parsing subscopes.

The goal is to eventually be very precise with scoping
information, once we have block scopes: one block scope might use
`eval', which would require the emission of a symbol table within
that block and containing blocks, whereas another block in the
same function might not, allowing us to not emit a symbol table.

  • parser/Nodes.h:

(JSC::ScopeFlags): Rename from CodeFeatures.
(JSC::ScopeNode::addScopeFlags):
(JSC::ScopeNode::scopeFlags): New accessors for m_scopeFlags.
(JSC::ScopeNode::isStrictMode):
(JSC::ScopeNode::usesEval):
(JSC::ScopeNode::usesArguments):
(JSC::ScopeNode::setUsesArguments):
(JSC::ScopeNode::usesThis):
(JSC::ScopeNode::needsActivationForMoreThanVariables):
(JSC::ScopeNode::needsActivation): Refactor these accessors to
operate on the m_scopeFlags member.
(JSC::ScopeNode::source):
(JSC::ScopeNode::sourceURL):
(JSC::ScopeNode::sourceID): Shuffle these definitions around; no
semantic change.
(JSC::ScopeNode::ScopeNode)
(JSC::ProgramNode::ProgramNode)
(JSC::EvalNode::EvalNode)
(JSC::FunctionBodyNode::FunctionBodyNode): Have these constructors
take a ScopeFlags as an argument, instead of a bool inStrictContext.

  • parser/Nodes.cpp:

(JSC::ScopeNode::ScopeNode):
(JSC::ProgramNode::ProgramNode):
(JSC::ProgramNode::create):
(JSC::EvalNode::EvalNode):
(JSC::EvalNode::create):
(JSC::FunctionBodyNode::FunctionBodyNode):
(JSC::FunctionBodyNode::create): Adapt constructors to change.

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::ASTBuilder):
(JSC::ASTBuilder::thisExpr):
(JSC::ASTBuilder::createResolve):
(JSC::ASTBuilder::createFunctionBody):
(JSC::ASTBuilder::createFuncDeclStatement):
(JSC::ASTBuilder::createTryStatement):
(JSC::ASTBuilder::createWithStatement):
(JSC::ASTBuilder::addVar):
(JSC::ASTBuilder::Scope::Scope):
(Scope):
(ASTBuilder):
(JSC::ASTBuilder::makeFunctionCallNode): Don't track scope
features here. Instead rely on the base Parser mechanism to track
features.

  • parser/NodeInfo.h (NodeInfo, NodeDeclarationInfo): "ScopeFlags".
  • parser/Parser.h:

(JSC::Scope::Scope): Manage scope through flags, not
bit-booleans. This lets us uniformly propagate them up and down.
(JSC::Scope::declareWrite):
(JSC::Scope::declareParameter):
(JSC::Scope::useVariable):
(JSC::Scope::collectFreeVariables):
(JSC::Scope::getCapturedVariables):
(JSC::Scope::saveFunctionInfo):
(JSC::Scope::restoreFunctionInfo):
(JSC::Parser::pushScope): Adapt to use scope flags and their
accessors instead of bit-booleans.

  • parser/Parser.cpp:

(JSC::::Parser):
(JSC::::parseInner):
(JSC::::didFinishParsing):
(JSC::::parseSourceElements):
(JSC::::parseVarDeclarationList):
(JSC::::parseConstDeclarationList):
(JSC::::parseWithStatement):
(JSC::::parseTryStatement):
(JSC::::parseFunctionBody):
(JSC::::parseFunctionInfo):
(JSC::::parseFunctionDeclaration):
(JSC::::parsePrimaryExpression): Hoist some of the flag handling
out of the "context" (ASTBuilder or SyntaxChecker) and to here.
Does not seem to have a performance impact.

  • parser/SourceProviderCacheItem.h (SourceProviderCacheItem):

Cache the scopeflags.

  • parser/SyntaxChecker.h: Remove evalCount() decl.
  • runtime/Executable.cpp:

(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::produceCodeBlockFor):

  • runtime/Executable.h:

(JSC::ScriptExecutable::ScriptExecutable):
(JSC::ScriptExecutable::usesEval):
(JSC::ScriptExecutable::usesArguments):
(JSC::ScriptExecutable::needsActivation):
(JSC::ScriptExecutable::isStrictMode):
(JSC::ScriptExecutable::recordParse):
(ScriptExecutable): ScopeFlags, not features.

File:
1 edited

Legend:

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

    r108935 r110287  
    6363
    6464    m_functionCache = source.provider()->cache();
    65     ScopeRef scope = pushScope();
     65    ScopeFlags scopeFlags = NoScopeFlags;
     66    if (strictness == JSParseStrict)
     67        scopeFlags |= StrictModeFlag;
    6668    if (parserMode == JSParseFunctionCode)
    67         scope->setIsFunction();
    68     if (strictness == JSParseStrict)
    69         scope->setStrictMode();
     69        scopeFlags |= FunctionModeFlag;
     70    ScopeRef scope = pushScope(scopeFlags);
    7071    if (parameters) {
    7172        for (unsigned i = 0; i < parameters->size(); i++)
     
    9798    IdentifierSet capturedVariables;
    9899    scope->getCapturedVariables(capturedVariables);
    99     CodeFeatures features = context.features();
    100     if (scope->strictMode())
    101         features |= StrictModeFeature;
    102     if (scope->shadowsArguments())
    103         features |= ShadowsArgumentsFeature;
     100    ScopeFlags scopeFlags = scope->modeFlags() | scope->usesFlags();
    104101    unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
    105102    if (functionCacheSize != oldFunctionCacheSize)
    106103        m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
    107104
    108     didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
     105    didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), scopeFlags,
    109106                     m_lastLine, context.numConstants(), capturedVariables);
    110107
     
    114111template <typename LexerType>
    115112void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack,
    116                               ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars)
     113                              ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, ScopeFlags scopeFlags, int lastLine, int numConstants, IdentifierSet& capturedVars)
    117114{
    118115    m_sourceElements = sourceElements;
     
    120117    m_funcDeclarations = funcStack;
    121118    m_capturedVariables.swap(capturedVars);
    122     m_features = features;
     119    m_scopeFlags = scopeFlags;
    123120    m_lastLine = lastLine;
    124121    m_numConstants = numConstants;
     
    148145                // "use strict" must be the exact literal without escape sequences or line continuation.
    149146                if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_globalData->propertyNames->useStrictIdentifier == *directive) {
    150                     setStrictMode();
     147                    currentScope()->setFlags(StrictModeFlag);
    151148                    hasSetStrict = true;
    152149                    failIfFalse(isValidStrictMode());
     
    256253        bool hasInitializer = match(EQUAL);
    257254        failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
     255        if (m_globalData->propertyNames->arguments == *name)
     256            currentScope()->setFlags(UsesArgumentsFlag);
    258257        context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
    259258        if (hasInitializer) {
     
    290289        bool hasInitializer = match(EQUAL);
    291290        declareVariable(name);
     291        if (m_globalData->propertyNames->arguments == *name)
     292            currentScope()->setFlags(UsesArgumentsFlag);
    292293        context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
    293294        TreeExpression initializer = 0;
     
    512513    ASSERT(match(WITH));
    513514    failIfTrueWithMessage(strictMode(), "'with' statements are not valid in strict mode");
    514     currentScope()->setNeedsFullActivation();
     515    currentScope()->setFlags(UsesWithFlag);
    515516    int startLine = tokenLine();
    516517    next();
     
    527528    failIfFalse(statement);
    528529   
     530    currentScope()->setFlags(UsesWithFlag);
    529531    return context.createWithStatement(m_lexer->lastLineNumber(), expr, statement, start, end, startLine, endLine);
    530532}
     
    615617   
    616618    if (match(CATCH)) {
    617         currentScope()->setNeedsFullActivation();
     619        currentScope()->setFlags(UsesCatchFlag);
    618620        next();
    619621        consumeOrFail(OPENPAREN);
     
    621623        ident = m_token.m_data.ident;
    622624        next();
    623         AutoPopScopeRef catchScope(this, pushScope());
     625        AutoPopScopeRef catchScope(this, pushScope(currentScope()->modeFlags()));
    624626        failIfFalseIfStrictWithNameAndMessage(declareVariable(ident), "Cannot declare a variable named", ident->impl(), "in strict mode");
    625         catchScope->preventNewDecls();
     627        currentScope()->setFlags(BlockScopeFlag | UsesCatchFlag);
    626628        consumeOrFail(CLOSEPAREN);
    627629        matchOrFail(OPENBRACE);
     
    760762{
    761763    if (match(CLOSEBRACE))
    762         return context.createFunctionBody(m_lexer->lastLineNumber(), strictMode());
     764        return context.createFunctionBody(m_lexer->lastLineNumber(), currentScope()->modeFlags());
    763765    DepthManager statementDepth(&m_statementDepth);
    764766    m_statementDepth = 0;
     
    771773template <FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
    772774{
    773     AutoPopScopeRef functionScope(this, pushScope());
    774     functionScope->setIsFunction();
     775    AutoPopScopeRef functionScope(this, pushScope(currentScope()->modeFlags() | FunctionModeFlag));
    775776    if (match(IDENT)) {
    776777        name = m_token.m_data.ident;
     
    794795    if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
    795796        // If we're in a strict context, the cached function info must say it was strict too.
    796         ASSERT(!strictMode() || cachedInfo->strictMode);
    797         body = context.createFunctionBody(m_lexer->lastLineNumber(), cachedInfo->strictMode);
     797        ASSERT(!strictMode() || (cachedInfo->scopeFlags & StrictModeFlag));
     798        body = context.createFunctionBody(m_lexer->lastLineNumber(), cachedInfo->scopeFlags);
    798799       
    799800        functionScope->restoreFunctionInfo(cachedInfo);
     
    855856    failIfFalse(name);
    856857    failIfFalseIfStrict(declareVariable(name));
     858    if (*name == m_globalData->propertyNames->arguments)
     859        currentScope()->setFlags(UsesArgumentsFlag);
    857860    return context.createFuncDeclStatement(m_lexer->lastLineNumber(), name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
    858861}
     
    14021405    case THISTOKEN: {
    14031406        next();
     1407        currentScope()->setFlags(UsesThisFlag);
    14041408        return context.thisExpr(m_lexer->lastLineNumber());
    14051409    }
     
    14081412        const Identifier* ident = m_token.m_data.ident;
    14091413        next();
    1410         currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
     1414        if (m_globalData->propertyNames->eval == *ident)
     1415            currentScope()->setFlags(UsesEvalFlag);
     1416        else if (m_globalData->propertyNames->arguments == *ident)
     1417            currentScope()->setFlags(UsesArgumentsFlag);
     1418        currentScope()->useVariable(ident);
    14111419        m_lastIdentifier = ident;
    14121420        return context.createResolve(m_lexer->lastLineNumber(), ident, start);
Note: See TracChangeset for help on using the changeset viewer.