Changeset 67769 in webkit for trunk/JavaScriptCore/parser


Ignore:
Timestamp:
Sep 17, 2010, 6:06:59 PM (15 years ago)
Author:
[email protected]
Message:

2010-09-17 Oliver Hunt <[email protected]>

Reviewed by Gavin Barraclough.

Imprecise tracking of variable capture leads to overly pessimistic creation of activations
https://bugs.webkit.org/show_bug.cgi?id=46020

The old logic for track free and captured variables would cause us
to decide we needed an activation in every function along the scope
chain between a variable capture and its declaration. We now track
captured variables precisely which requires a bit of additional work

The most substantial change is that the parsing routine needs to
be passed the list of function parameters when reparsing a function
as when reparsing we don't parse the function declaration itself only
its body.

  • JavaScriptCore.exp:
  • parser/JSParser.cpp: (JSC::JSParser::Scope::Scope): (JSC::JSParser::Scope::needsFullActivation):

We need to distinguish between use of a feature that requires
an activation and eval so we now get this additional flag.

(JSC::JSParser::Scope::collectFreeVariables):
(JSC::JSParser::Scope::getCapturedVariables):

We can't simply return the list of "capturedVariables" now as
is insufficiently precise, so we compute them instead.

(JSC::JSParser::popScope):
(JSC::jsParse):
(JSC::JSParser::JSParser):
(JSC::JSParser::parseProgram):
(JSC::JSParser::parseWithStatement):
(JSC::JSParser::parseTryStatement):
(JSC::JSParser::parseFunctionInfo):
(JSC::JSParser::parseFunctionDeclaration):
(JSC::JSParser::parseProperty):
(JSC::JSParser::parseMemberExpression):

  • parser/JSParser.h:
  • parser/Parser.cpp: (JSC::Parser::parse):
  • parser/Parser.h: (JSC::Parser::parse):
  • runtime/Executable.cpp: (JSC::EvalExecutable::compileInternal): (JSC::ProgramExecutable::checkSyntax): (JSC::ProgramExecutable::compileInternal): (JSC::FunctionExecutable::compileForCallInternal): (JSC::FunctionExecutable::compileForConstructInternal): (JSC::FunctionExecutable::reparseExceptionInfo): (JSC::EvalExecutable::reparseExceptionInfo): (JSC::FunctionExecutable::fromGlobalCode):

Pass function parameters (if available) to the parser.

Location:
trunk/JavaScriptCore/parser
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/parser/JSParser.cpp

    r67583 r67769  
    6868class JSParser {
    6969public:
    70     JSParser(Lexer*, JSGlobalData*, SourceProvider*);
     70    JSParser(Lexer*, JSGlobalData*, FunctionParameters*, SourceProvider*);
    7171    bool parseProgram();
    7272private:
     
    162162    template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
    163163    enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
    164     template <FunctionRequirements, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
     164    template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
    165165    ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
    166166    bool allowAutomaticSemicolon();
     
    204204        Scope()
    205205            : m_usesEval(false)
     206            , m_needsFullActivation(false)
    206207        {
    207208        }
     
    218219        }
    219220       
    220         void collectFreeVariables(Scope* nestedScope, bool shouldTrackCapturedVariables)
     221        void needsFullActivation() { m_needsFullActivation = true; }
     222       
     223        void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
    221224        {
    222225            if (nestedScope->m_usesEval)
     
    227230                    continue;
    228231                m_usedVariables.add(*ptr);
    229                 if (shouldTrackCapturedVariables)
    230                     m_capturedVariables.add(*ptr);
     232                if (shouldTrackClosedVariables)
     233                    m_closedVariables.add(*ptr);
    231234            }
    232235        }
    233236
    234         IdentifierSet& capturedVariables() { return m_capturedVariables; }
     237        void getCapturedVariables(IdentifierSet& capturedVariables)
     238        {
     239            if (m_needsFullActivation || m_usesEval) {
     240                capturedVariables.swap(m_declaredVariables);
     241                return;
     242            }
     243            for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
     244                if (!m_declaredVariables.contains(*ptr))
     245                    continue;
     246                capturedVariables.add(*ptr);
     247            }
     248        }
    235249    private:
    236250        bool m_usesEval;
     251        bool m_needsFullActivation;
    237252        IdentifierSet m_declaredVariables;
    238253        IdentifierSet m_usedVariables;
    239         IdentifierSet m_capturedVariables;
     254        IdentifierSet m_closedVariables;
    240255    };
    241256   
     
    266281    }
    267282
    268     void popScope(ScopeRef scope, bool shouldTrackCapturedVariables)
     283    void popScope(ScopeRef scope, bool shouldTrackClosedVariables)
    269284    {
    270285        ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
    271286        ASSERT(m_scopeStack.size() > 1);
    272         m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackCapturedVariables);
     287        m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
    273288        m_scopeStack.removeLast();
    274289    }
     
    277292};
    278293
    279 int jsParse(JSGlobalData* globalData, const SourceCode* source)
    280 {
    281     JSParser parser(globalData->lexer, globalData, source->provider());
     294int jsParse(JSGlobalData* globalData, FunctionParameters* parameters, const SourceCode* source)
     295{
     296    JSParser parser(globalData->lexer, globalData, parameters, source->provider());
    282297    return parser.parseProgram();
    283298}
    284299
    285 JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provider)
     300JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, SourceProvider* provider)
    286301    : m_lexer(lexer)
    287302    , m_endAddress(0)
     
    299314    next();
    300315    m_lexer->setLastLineNumber(tokenLine());
     316    ScopeRef scope = pushScope();
     317    if (parameters) {
     318        for (unsigned i = 0; i < parameters->size(); i++)
     319            scope->declareVariable(&parameters->at(i));
     320    }
    301321}
    302322
     
    304324{
    305325    ASTBuilder context(m_globalData, m_lexer);
    306     ScopeRef scope = pushScope();
     326    ScopeRef scope = currentScope();
    307327    SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
    308328    if (!sourceElements || !consume(EOFTOK))
    309329        return true;
     330    IdentifierSet capturedVariables;
     331    scope->getCapturedVariables(capturedVariables);
    310332    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
    311                                           m_lastLine, context.numConstants(), scope->capturedVariables());
     333                                          m_lastLine, context.numConstants(), capturedVariables);
    312334    return false;
    313335}
     
    631653{
    632654    ASSERT(match(WITH));
     655    currentScope()->needsFullActivation();
    633656    int startLine = tokenLine();
    634657    next();
     
    729752
    730753    if (match(CATCH)) {
     754        currentScope()->needsFullActivation();
    731755        next();
    732756        consumeOrFail(OPENPAREN);
     
    864888}
    865889
    866 template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
     890template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
    867891{
    868892    ScopeRef functionScope = pushScope();
     
    870894        name = m_token.m_data.ident;
    871895        next();
    872         functionScope->declareVariable(name);
     896        if (!nameIsInContainingScope)
     897            functionScope->declareVariable(name);
    873898    } else if (requirements == FunctionNeedsName)
    874899        return false;
     
    907932    int closeBracePos = 0;
    908933    int bodyStartLine = 0;
    909     failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
     934    failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
    910935    failIfFalse(name);
    911936    currentScope()->declareVariable(name);
     
    12001225        else
    12011226            fail();
    1202         failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine));
     1227        failIfFalse((parseFunctionInfo<FunctionNeedsName, false>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
    12031228        return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
    12041229    }
     
    14521477        int bodyStartLine = 0;
    14531478        next();
    1454         failIfFalse(parseFunctionInfo<FunctionNoRequirements>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
     1479        failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
    14551480        base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
    14561481    } else
  • trunk/JavaScriptCore/parser/JSParser.h

    r63566 r67769  
    2929namespace JSC {
    3030
     31class FunctionParameters;
    3132class Identifier;
    3233class JSGlobalData;
     
    155156};
    156157
    157 int jsParse(JSGlobalData*, const SourceCode*);
     158int jsParse(JSGlobalData*, FunctionParameters*, const SourceCode*);
    158159}
    159160#endif // JSParser_h
  • trunk/JavaScriptCore/parser/Parser.cpp

    r67583 r67769  
    3636namespace JSC {
    3737
    38 void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
     38void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, int* errLine, UString* errMsg)
    3939{
    4040    m_sourceElements = 0;
     
    5454    lexer.setCode(*m_source, m_arena);
    5555
    56     int parseError = jsParse(globalData, m_source);
     56    int parseError = jsParse(globalData, parameters, m_source);
    5757    int lineNumber = lexer.lineNumber();
    5858    bool lexError = lexer.sawError();
  • trunk/JavaScriptCore/parser/Parser.h

    r67583 r67769  
    4949    public:
    5050        template <class ParsedNode>
    51         PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, JSObject** exception);
     51        PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, FunctionParameters*, JSObject** exception);
    5252
    5353        void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*,
     
    5858
    5959    private:
    60         void parse(JSGlobalData*, int* errLine, UString* errMsg);
     60        void parse(JSGlobalData*, FunctionParameters*, int* errLine, UString* errMsg);
    6161
    6262        // Used to determine type of error to report.
     
    7676
    7777    template <class ParsedNode>
    78     PassRefPtr<ParsedNode> Parser::parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, JSObject** exception)
     78    PassRefPtr<ParsedNode> Parser::parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, FunctionParameters* parameters, JSObject** exception)
    7979    {
    8080        ASSERT(exception && !*exception);
     
    8585        if (ParsedNode::scopeIsFunction)
    8686            globalData->lexer->setIsReparsing();
    87         parse(globalData, &errLine, &errMsg);
     87        parse(globalData, parameters, &errLine, &errMsg);
    8888
    8989        RefPtr<ParsedNode> result;
Note: See TracChangeset for help on using the changeset viewer.