2010-09-15 Oliver Hunt <oliver@apple.com>
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Sep 2010 00:05:13 +0000 (00:05 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Sep 2010 00:05:13 +0000 (00:05 +0000)
        Reviewed by Geoffrey Garen.

        Use free variable analysis to improve activation performance
        https://bugs.webkit.org/show_bug.cgi?id=45837

        Adds free and captured variable tracking to the JS parser.  This
        allows us to avoid construction of an activation object in some
        cases.  Future patches will make more use of this information to
        improve those cases where activations are still needed.

        * parser/ASTBuilder.h:
        * parser/JSParser.cpp:
        (JSC::JSParser::Scope::Scope):
        (JSC::JSParser::Scope::declareVariable):
        (JSC::JSParser::Scope::useVariable):
        (JSC::JSParser::Scope::collectFreeVariables):
        (JSC::JSParser::Scope::capturedVariables):
        (JSC::JSParser::ScopeRef::ScopeRef):
        (JSC::JSParser::ScopeRef::operator->):
        (JSC::JSParser::ScopeRef::index):
        (JSC::JSParser::currentScope):
        (JSC::JSParser::pushScope):
        (JSC::JSParser::popScope):
        (JSC::JSParser::parseProgram):
        (JSC::JSParser::parseVarDeclarationList):
        (JSC::JSParser::parseConstDeclarationList):
        (JSC::JSParser::parseTryStatement):
        (JSC::JSParser::parseFormalParameters):
        (JSC::JSParser::parseFunctionInfo):
        (JSC::JSParser::parseFunctionDeclaration):
        (JSC::JSParser::parsePrimaryExpression):
        * parser/Nodes.cpp:
        (JSC::ScopeNodeData::ScopeNodeData):
        (JSC::ScopeNode::ScopeNode):
        (JSC::ProgramNode::ProgramNode):
        (JSC::ProgramNode::create):
        (JSC::EvalNode::EvalNode):
        (JSC::EvalNode::create):
        (JSC::FunctionBodyNode::FunctionBodyNode):
        (JSC::FunctionBodyNode::create):
        * parser/Nodes.h:
        (JSC::ScopeNode::needsActivation):
        (JSC::ScopeNode::hasCapturedVariables):
        * parser/Parser.cpp:
        (JSC::Parser::didFinishParsing):
        * parser/Parser.h:
        (JSC::Parser::parse):
        * parser/SyntaxChecker.h:
        * runtime/Executable.cpp:
        (JSC::EvalExecutable::compileInternal):
        (JSC::ProgramExecutable::compileInternal):
        (JSC::FunctionExecutable::compileForCallInternal):
        (JSC::FunctionExecutable::compileForConstructInternal):
        * runtime/Executable.h:
        (JSC::ScriptExecutable::needsActivation):
        (JSC::ScriptExecutable::recordParse):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@67583 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/parser/ASTBuilder.h
JavaScriptCore/parser/JSParser.cpp
JavaScriptCore/parser/Nodes.cpp
JavaScriptCore/parser/Nodes.h
JavaScriptCore/parser/Parser.cpp
JavaScriptCore/parser/Parser.h
JavaScriptCore/parser/SyntaxChecker.h
JavaScriptCore/runtime/Executable.cpp
JavaScriptCore/runtime/Executable.h

index a459e3f..cabc758 100644 (file)
@@ -1,3 +1,62 @@
+2010-09-15  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Geoffrey Garen.
+
+        Use free variable analysis to improve activation performance
+        https://bugs.webkit.org/show_bug.cgi?id=45837
+
+        Adds free and captured variable tracking to the JS parser.  This
+        allows us to avoid construction of an activation object in some
+        cases.  Future patches will make more use of this information to
+        improve those cases where activations are still needed.
+
+        * parser/ASTBuilder.h:
+        * parser/JSParser.cpp:
+        (JSC::JSParser::Scope::Scope):
+        (JSC::JSParser::Scope::declareVariable):
+        (JSC::JSParser::Scope::useVariable):
+        (JSC::JSParser::Scope::collectFreeVariables):
+        (JSC::JSParser::Scope::capturedVariables):
+        (JSC::JSParser::ScopeRef::ScopeRef):
+        (JSC::JSParser::ScopeRef::operator->):
+        (JSC::JSParser::ScopeRef::index):
+        (JSC::JSParser::currentScope):
+        (JSC::JSParser::pushScope):
+        (JSC::JSParser::popScope):
+        (JSC::JSParser::parseProgram):
+        (JSC::JSParser::parseVarDeclarationList):
+        (JSC::JSParser::parseConstDeclarationList):
+        (JSC::JSParser::parseTryStatement):
+        (JSC::JSParser::parseFormalParameters):
+        (JSC::JSParser::parseFunctionInfo):
+        (JSC::JSParser::parseFunctionDeclaration):
+        (JSC::JSParser::parsePrimaryExpression):
+        * parser/Nodes.cpp:
+        (JSC::ScopeNodeData::ScopeNodeData):
+        (JSC::ScopeNode::ScopeNode):
+        (JSC::ProgramNode::ProgramNode):
+        (JSC::ProgramNode::create):
+        (JSC::EvalNode::EvalNode):
+        (JSC::EvalNode::create):
+        (JSC::FunctionBodyNode::FunctionBodyNode):
+        (JSC::FunctionBodyNode::create):
+        * parser/Nodes.h:
+        (JSC::ScopeNode::needsActivation):
+        (JSC::ScopeNode::hasCapturedVariables):
+        * parser/Parser.cpp:
+        (JSC::Parser::didFinishParsing):
+        * parser/Parser.h:
+        (JSC::Parser::parse):
+        * parser/SyntaxChecker.h:
+        * runtime/Executable.cpp:
+        (JSC::EvalExecutable::compileInternal):
+        (JSC::ProgramExecutable::compileInternal):
+        (JSC::FunctionExecutable::compileForCallInternal):
+        (JSC::FunctionExecutable::compileForConstructInternal):
+        * runtime/Executable.h:
+        (JSC::ScriptExecutable::needsActivation):
+        (JSC::ScriptExecutable::recordParse):
+
 2010-09-14  Hyung Song  <beergun@company100.net>
 
         Reviewed by Kent Tamura.
index dbf3c07..40023f8 100644 (file)
@@ -100,6 +100,7 @@ public:
     typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
     
     static const bool CreatesAST = true;
+    static const bool NeedsFreeVariableInfo = true;
 
     ExpressionNode* makeBinaryNode(int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
     ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end);
index 820811e..715750c 100644 (file)
@@ -199,6 +199,81 @@ private:
     int m_assignmentCount;
     int m_nonLHSCount;
     bool m_syntaxAlreadyValidated;
+
+    struct Scope {
+        Scope()
+            : m_usesEval(false)
+        {
+        }
+        
+        void declareVariable(const Identifier* ident)
+        {
+            m_declaredVariables.add(ident->ustring().impl());
+        }
+        
+        void useVariable(const Identifier* ident, bool isEval)
+        {
+            m_usesEval |= isEval;
+            m_usedVariables.add(ident->ustring().impl());
+        }
+        
+        void collectFreeVariables(Scope* nestedScope, bool shouldTrackCapturedVariables)
+        {
+            if (nestedScope->m_usesEval)
+                m_usesEval = true;
+            IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
+            for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
+                if (nestedScope->m_declaredVariables.contains(*ptr))
+                    continue;
+                m_usedVariables.add(*ptr);
+                if (shouldTrackCapturedVariables)
+                    m_capturedVariables.add(*ptr);
+            }
+        }
+
+        IdentifierSet& capturedVariables() { return m_capturedVariables; }
+    private:
+        bool m_usesEval;
+        IdentifierSet m_declaredVariables;
+        IdentifierSet m_usedVariables;
+        IdentifierSet m_capturedVariables;
+    };
+    
+    typedef Vector<Scope, 10> ScopeStack;
+
+    struct ScopeRef {
+        ScopeRef(ScopeStack* scopeStack, unsigned index)
+            : m_scopeStack(scopeStack)
+            , m_index(index)
+        {
+        }
+        Scope* operator->() { return &m_scopeStack->at(m_index); }
+        unsigned index() const { return m_index; }
+    private:
+        ScopeStack* m_scopeStack;
+        unsigned m_index;
+    };
+    
+    ScopeRef currentScope()
+    {
+        return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
+    }
+    
+    ScopeRef pushScope()
+    {
+        m_scopeStack.append(Scope());
+        return currentScope();
+    }
+
+    void popScope(ScopeRef scope, bool shouldTrackCapturedVariables)
+    {
+        ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
+        ASSERT(m_scopeStack.size() > 1);
+        m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackCapturedVariables);
+        m_scopeStack.removeLast();
+    }
+
+    ScopeStack m_scopeStack;
 };
 
 int jsParse(JSGlobalData* globalData, const SourceCode* source)
@@ -228,11 +303,12 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provi
 bool JSParser::parseProgram()
 {
     ASTBuilder context(m_globalData, m_lexer);
+    ScopeRef scope = pushScope();
     SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
     if (!sourceElements || !consume(EOFTOK))
         return true;
     m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
-                                          m_lastLine, context.numConstants());
+                                          m_lastLine, context.numConstants(), scope->capturedVariables());
     return false;
 }
 
@@ -327,6 +403,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr
         lastIdent = name;
         next();
         bool hasInitializer = match(EQUAL);
+        currentScope()->declareVariable(name);
         context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
         if (hasInitializer) {
             int varDivot = tokenStart() + 1;
@@ -358,6 +435,7 @@ template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationLi
         const Identifier* name = m_token.m_data.ident;
         next();
         bool hasInitializer = match(EQUAL);
+        currentScope()->declareVariable(name);
         context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
         TreeExpression initializer = 0;
         if (hasInitializer) {
@@ -655,12 +733,15 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild
         matchOrFail(IDENT);
         ident = m_token.m_data.ident;
         next();
+        ScopeRef catchScope = pushScope();
+        catchScope->declareVariable(ident);
         consumeOrFail(CLOSEPAREN);
         matchOrFail(OPENBRACE);
         int initialEvalCount = context.evalCount();
         catchBlock = parseBlockStatement(context);
         failIfFalse(catchBlock);
         catchHasEval = initialEvalCount != context.evalCount();
+        popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
     }
 
     if (match(FINALLY)) {
@@ -757,6 +838,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
 {
     matchOrFail(IDENT);
     usesArguments = m_globalData->propertyNames->arguments == *m_token.m_data.ident;
+    currentScope()->declareVariable(m_token.m_data.ident);
     TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
     TreeFormalParameterList tail = list;
     next();
@@ -764,6 +846,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
         next();
         matchOrFail(IDENT);
         const Identifier* ident = m_token.m_data.ident;
+        currentScope()->declareVariable(ident);
         next();
         usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident;
         tail = context.createFormalParameterList(tail, *ident);
@@ -782,9 +865,11 @@ template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBu
 
 template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
 {
+    ScopeRef functionScope = pushScope();
     if (match(IDENT)) {
         name = m_token.m_data.ident;
         next();
+        functionScope->declareVariable(name);
     } else if (requirements == FunctionNeedsName)
         return false;
     consumeOrFail(OPENPAREN);
@@ -804,7 +889,7 @@ template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool J
     failIfFalse(body);
     if (usesArguments)
         context.setUsesArguments(body);
-
+    popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
     matchOrFail(CLOSEBRACE);
     closeBracePos = m_token.m_data.intValue;
     next();
@@ -823,6 +908,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(Tr
     int bodyStartLine = 0;
     failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
     failIfFalse(name);
+    currentScope()->declareVariable(name);
     return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
 }
 
@@ -1281,6 +1367,7 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre
         int start = tokenStart();
         const Identifier* ident = m_token.m_data.ident;
         next();
+        currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
         return context.createResolve(ident, start);
     }
     case STRING: {
index c41d735..534e28a 100644 (file)
@@ -75,7 +75,7 @@ StatementNode* SourceElements::singleStatement() const
 
 // -----------------------------ScopeNodeData ---------------------------
 
-ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, int numConstants)
+ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, int numConstants)
     : m_numConstants(numConstants)
     , m_statements(statements)
 {
@@ -84,6 +84,7 @@ ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, Var
         m_varStack.swap(*varStack);
     if (funcStack)
         m_functionStack.swap(*funcStack);
+    m_capturedVariables.swap(capturedVariables);
 }
 
 // ------------------------------ ScopeNode -----------------------------
@@ -95,10 +96,10 @@ ScopeNode::ScopeNode(JSGlobalData* globalData)
 {
 }
 
-ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
+ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, CodeFeatures features, int numConstants)
     : StatementNode(globalData)
     , ParserArenaRefCounted(globalData)
-    , m_data(adoptPtr(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, numConstants)))
+    , m_data(adoptPtr(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, capturedVariables, numConstants)))
     , m_features(features)
     , m_source(source)
 {
@@ -111,14 +112,14 @@ StatementNode* ScopeNode::singleStatement() const
 
 // ------------------------------ ProgramNode -----------------------------
 
-inline ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
-    : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
+inline ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+    : ScopeNode(globalData, source, children, varStack, funcStack, capturedVariables, features, numConstants)
 {
 }
 
-PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
+PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
 {
-    RefPtr<ProgramNode> node = new ProgramNode(globalData, children, varStack, funcStack, source, features, numConstants);
+    RefPtr<ProgramNode> node = new ProgramNode(globalData, children, varStack, funcStack, capturedVariables, source, features, numConstants);
 
     ASSERT(node->data()->m_arena.last() == node);
     node->data()->m_arena.removeLast();
@@ -129,14 +130,14 @@ PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElem
 
 // ------------------------------ EvalNode -----------------------------
 
-inline EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
-    : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
+inline EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+    : ScopeNode(globalData, source, children, varStack, funcStack, capturedVariables, features, numConstants)
 {
 }
 
-PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
+PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
 {
-    RefPtr<EvalNode> node = new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants);
+    RefPtr<EvalNode> node = new EvalNode(globalData, children, varStack, funcStack, capturedVariables, source, features, numConstants);
 
     ASSERT(node->data()->m_arena.last() == node);
     node->data()->m_arena.removeLast();
@@ -158,8 +159,8 @@ inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
 {
 }
 
-inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
-    : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants)
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+    : ScopeNode(globalData, sourceCode, children, varStack, funcStack, capturedVariables, features, numConstants)
 {
 }
 
@@ -181,9 +182,9 @@ FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
     return new FunctionBodyNode(globalData);
 }
 
-PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
 {
-    RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants);
+    RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, children, varStack, funcStack, capturedVariables, sourceCode, features, numConstants);
 
     ASSERT(node->data()->m_arena.last() == node);
     node->data()->m_arena.removeLast();
index d25079b..2d8448c 100644 (file)
@@ -81,6 +81,8 @@ namespace JSC {
         OpLogicalOr
     };
 
+    typedef HashSet<RefPtr<StringImpl>, IdentifierRepHash> IdentifierSet;
+
     namespace DeclarationStacks {
         enum VarAttrs { IsConstant = 1, HasInitializer = 2 };
         typedef Vector<std::pair<const Identifier*, unsigned> > VarStack;
@@ -1376,13 +1378,14 @@ namespace JSC {
         typedef DeclarationStacks::VarStack VarStack;
         typedef DeclarationStacks::FunctionStack FunctionStack;
 
-        ScopeNodeData(ParserArena&, SourceElements*, VarStack*, FunctionStack*, int numConstants);
+        ScopeNodeData(ParserArena&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, int numConstants);
 
         ParserArena m_arena;
         VarStack m_varStack;
         FunctionStack m_functionStack;
         int m_numConstants;
         SourceElements* m_statements;
+        IdentifierSet m_capturedVariables;
     };
 
     class ScopeNode : public StatementNode, public ParserArenaRefCounted {
@@ -1391,7 +1394,7 @@ namespace JSC {
         typedef DeclarationStacks::FunctionStack FunctionStack;
 
         ScopeNode(JSGlobalData*);
-        ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants);
+        ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, CodeFeatures, int numConstants);
 
         using ParserArenaRefCounted::operator new;
 
@@ -1409,7 +1412,8 @@ namespace JSC {
         bool usesArguments() const { return m_features & ArgumentsFeature; }
         void setUsesArguments() { m_features |= ArgumentsFeature; }
         bool usesThis() const { return m_features & ThisFeature; }
-        bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
+        bool needsActivation() const { ASSERT(m_data); return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature | CatchFeature)); }
+        bool hasCapturedVariables() const { return !!m_data->m_capturedVariables.size(); }
 
         VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; }
         FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; }
@@ -1437,24 +1441,24 @@ namespace JSC {
 
     class ProgramNode : public ScopeNode {
     public:
-        static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+        static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         static const bool scopeIsFunction = false;
 
     private:
-        ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+        ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
     };
 
     class EvalNode : public ScopeNode {
     public:
-        static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+        static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         static const bool scopeIsFunction = false;
 
     private:
-        EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+        EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
     };
@@ -1470,7 +1474,7 @@ namespace JSC {
     class FunctionBodyNode : public ScopeNode {
     public:
         static FunctionBodyNode* create(JSGlobalData*);
-        static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+        static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         FunctionParameters* parameters() const { return m_parameters.get(); }
         size_t parameterCount() const { return m_parameters->size(); }
@@ -1486,7 +1490,7 @@ namespace JSC {
 
     private:
         FunctionBodyNode(JSGlobalData*);
-        FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants);
+        FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
 
         Identifier m_ident;
         RefPtr<FunctionParameters> m_parameters;
index 3bd352d..4d72ff7 100644 (file)
@@ -66,11 +66,12 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
 }
 
 void Parser::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, 
-                              ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants)
+                              ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars)
 {
     m_sourceElements = sourceElements;
     m_varDeclarations = varStack;
     m_funcDeclarations = funcStack;
+    m_capturedVariables.swap(capturedVars);
     m_features = features;
     m_lastLine = lastLine;
     m_numConstants = numConstants;
index c167980..0f8accb 100644 (file)
@@ -51,7 +51,8 @@ namespace JSC {
         PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, JSObject** exception);
 
         void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*, 
-                              ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants);
+                              ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features,
+                              int lastLine, int numConstants, IdentifierSet&);
 
         ParserArena& arena() { return m_arena; }
 
@@ -67,6 +68,7 @@ namespace JSC {
         SourceElements* m_sourceElements;
         ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
         ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+        IdentifierSet m_capturedVariables;
         CodeFeatures m_features;
         int m_lastLine;
         int m_numConstants;
@@ -87,12 +89,13 @@ namespace JSC {
         RefPtr<ParsedNode> result;
         if (m_sourceElements) {
             result = ParsedNode::create(globalData,
-            m_sourceElements,
-            m_varDeclarations ? &m_varDeclarations->data : 0,
-            m_funcDeclarations ? &m_funcDeclarations->data : 0,
-            source,
-            m_features,
-            m_numConstants);
+                m_sourceElements,
+                m_varDeclarations ? &m_varDeclarations->data : 0,
+                m_funcDeclarations ? &m_funcDeclarations->data : 0,
+                m_capturedVariables,
+                source,
+                m_features,
+                m_numConstants);
             result->setLoc(m_source->firstLine(), m_lastLine);
         } else if (lexicalGlobalObject) {
             // We can never see a syntax error when reparsing a function, since we should have
index e05facd..ce3ab61 100644 (file)
@@ -70,6 +70,7 @@ public:
     typedef int BinaryOperand;
     
     static const bool CreatesAST = false;
+    static const bool NeedsFreeVariableInfo = false;
 
     int createSourceElements() { return 1; }
     int makeFunctionCallNode(int, int, int, int, int) { return 1; }
index 41b5f1f..b41d911 100644 (file)
@@ -101,7 +101,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope
         ASSERT(exception);
         return exception;
     }
-    recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine());
+    recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
 
     ScopeChain scopeChain(scopeChainNode);
     JSGlobalObject* globalObject = scopeChain.globalObject();
@@ -150,7 +150,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc
         ASSERT(exception);
         return exception;
     }
-    recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine());
+    recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
 
     ScopeChain scopeChain(scopeChainNode);
     JSGlobalObject* globalObject = scopeChain.globalObject();
@@ -186,7 +186,7 @@ JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChain
     if (m_forceUsesArguments)
         body->setUsesArguments();
     body->finishParsing(m_parameters, m_name);
-    recordParse(body->features(), body->lineNo(), body->lastLine());
+    recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
 
     ScopeChain scopeChain(scopeChainNode);
     JSGlobalObject* globalObject = scopeChain.globalObject();
@@ -227,7 +227,7 @@ JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, Scope
     if (m_forceUsesArguments)
         body->setUsesArguments();
     body->finishParsing(m_parameters, m_name);
-    recordParse(body->features(), body->lineNo(), body->lastLine());
+    recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
 
     ScopeChain scopeChain(scopeChainNode);
     JSGlobalObject* globalObject = scopeChain.globalObject();
index 10dfb34..c168ac8 100644 (file)
@@ -172,20 +172,22 @@ namespace JSC {
 
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return m_features & ArgumentsFeature; }
-        bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
+        bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
 
         virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
 
     protected:
-        void recordParse(CodeFeatures features, int firstLine, int lastLine)
+        void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
         {
             m_features = features;
+            m_hasCapturedVariables = hasCapturedVariables;
             m_firstLine = firstLine;
             m_lastLine = lastLine;
         }
 
         SourceCode m_source;
         CodeFeatures m_features;
+        bool m_hasCapturedVariables;
         int m_firstLine;
         int m_lastLine;
     };