Reviewed by Eric.
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Dec 2007 10:13:00 +0000 (10:13 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Dec 2007 10:13:00 +0000 (10:13 +0000)
        - Optimize variable declarations
        http://bugs.webkit.org/show_bug.cgi?id=16585

        3.5% speedup on SunSpider.

        var statements now result in either assignments or empty statements.

        This allows a couple of optimization opportunities:
        - No need to branch at runtime to check if there is an initializer
        - EmptyStatementNodes can be removed entirely (also done in this patch)
        - Assignment expressions get properly optimized for local variables

        This patch also includes some code cleanup:
        - Most of the old VarStatement/VarDecl logic is now only used for const declarations,
          thus it is renamed appropriately
        - AssignExprNode is gone

        * JavaScriptCore.exp:
        * kjs/NodeInfo.h:
        * kjs/grammar.y:
        * kjs/nodes.cpp:
        (KJS::SourceElements::append):
        (KJS::ConstDeclNode::ConstDeclNode):
        (KJS::ConstDeclNode::optimizeVariableAccess):
        (KJS::ConstDeclNode::handleSlowCase):
        (KJS::ConstDeclNode::evaluateSingle):
        (KJS::ConstDeclNode::evaluate):
        (KJS::ConstStatementNode::optimizeVariableAccess):
        (KJS::ConstStatementNode::execute):
        (KJS::VarStatementNode::optimizeVariableAccess):
        (KJS::VarStatementNode::execute):
        (KJS::ForInNode::ForInNode):
        (KJS::ForInNode::optimizeVariableAccess):
        (KJS::ForInNode::execute):
        (KJS::FunctionBodyNode::initializeSymbolTable):
        (KJS::ProgramNode::initializeSymbolTable):
        (KJS::FunctionBodyNode::processDeclarations):
        (KJS::ProgramNode::processDeclarations):
        (KJS::EvalNode::processDeclarations):
        * kjs/nodes.h:
        (KJS::DeclarationStacks::):
        (KJS::StatementNode::):
        (KJS::ConstDeclNode::):
        (KJS::ConstStatementNode::):
        (KJS::EmptyStatementNode::):
        (KJS::VarStatementNode::):
        (KJS::ForNode::):
        * kjs/nodes2string.cpp:
        (KJS::ConstDeclNode::streamTo):
        (KJS::ConstStatementNode::streamTo):
        (KJS::ScopeNode::streamTo):
        (KJS::VarStatementNode::streamTo):
        (KJS::ForNode::streamTo):
        (KJS::ForInNode::streamTo):

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

JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/kjs/NodeInfo.h
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp

index 876279b270301ff6c22f6c560073f21f17021ccc..5683fea57d35d0d389dfde83057f67718a7bced5 100644 (file)
@@ -1,3 +1,62 @@
+2007-12-24  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Eric.
+
+        - Optimize variable declarations
+        http://bugs.webkit.org/show_bug.cgi?id=16585
+        
+        3.5% speedup on SunSpider.
+
+        var statements now result in either assignments or empty statements.
+        
+        This allows a couple of optimization opportunities:
+        - No need to branch at runtime to check if there is an initializer
+        - EmptyStatementNodes can be removed entirely (also done in this patch)
+        - Assignment expressions get properly optimized for local variables
+        
+        This patch also includes some code cleanup:
+        - Most of the old VarStatement/VarDecl logic is now only used for const declarations, 
+          thus it is renamed appropriately
+        - AssignExprNode is gone
+        
+        * JavaScriptCore.exp:
+        * kjs/NodeInfo.h:
+        * kjs/grammar.y:
+        * kjs/nodes.cpp:
+        (KJS::SourceElements::append):
+        (KJS::ConstDeclNode::ConstDeclNode):
+        (KJS::ConstDeclNode::optimizeVariableAccess):
+        (KJS::ConstDeclNode::handleSlowCase):
+        (KJS::ConstDeclNode::evaluateSingle):
+        (KJS::ConstDeclNode::evaluate):
+        (KJS::ConstStatementNode::optimizeVariableAccess):
+        (KJS::ConstStatementNode::execute):
+        (KJS::VarStatementNode::optimizeVariableAccess):
+        (KJS::VarStatementNode::execute):
+        (KJS::ForInNode::ForInNode):
+        (KJS::ForInNode::optimizeVariableAccess):
+        (KJS::ForInNode::execute):
+        (KJS::FunctionBodyNode::initializeSymbolTable):
+        (KJS::ProgramNode::initializeSymbolTable):
+        (KJS::FunctionBodyNode::processDeclarations):
+        (KJS::ProgramNode::processDeclarations):
+        (KJS::EvalNode::processDeclarations):
+        * kjs/nodes.h:
+        (KJS::DeclarationStacks::):
+        (KJS::StatementNode::):
+        (KJS::ConstDeclNode::):
+        (KJS::ConstStatementNode::):
+        (KJS::EmptyStatementNode::):
+        (KJS::VarStatementNode::):
+        (KJS::ForNode::):
+        * kjs/nodes2string.cpp:
+        (KJS::ConstDeclNode::streamTo):
+        (KJS::ConstStatementNode::streamTo):
+        (KJS::ScopeNode::streamTo):
+        (KJS::VarStatementNode::streamTo):
+        (KJS::ForNode::streamTo):
+        (KJS::ForInNode::streamTo):
+
 2007-12-21  Mark Rowe  <mrowe@apple.com>
 
         Reviewed by Oliver Hunt.
index 02cbd3fd62ab669ac519da1743853a96d0eaeaf6..03f15af92306e743bf0051c83a80be1554a2337b 100644 (file)
@@ -120,7 +120,7 @@ __ZN3KJS11Interpreter8evaluateEPNS_9ExecStateERKNS_7UStringEiS5_PNS_7JSValueE
 __ZN3KJS11JSImmediate4typeEPKNS_7JSValueE
 __ZN3KJS11JSImmediate8toObjectEPKNS_7JSValueEPNS_9ExecStateE
 __ZN3KJS11JSImmediate8toStringEPKNS_7JSValueE
-__ZN3KJS11ProgramNodeC1EPNS_14SourceElementsEPN3WTF6VectorIPNS_11VarDeclNodeELm16EEEPNS4_IPNS_12FuncDeclNodeELm16EEE
+__ZN3KJS11ProgramNodeC1EPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS4_IPNS_12FuncDeclNodeELm16EEE
 __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierE
 __ZN3KJS11PropertyMap5clearEv
 __ZN3KJS11PropertyMap7restoreERKNS_15SavedPropertiesE
index a5ce7627b62c7769514583883820f3024fc1f5e4..60637f2de9f8c783e10e0133b227f43ce58cfcf3 100644 (file)
@@ -36,7 +36,8 @@ typedef NodeInfo<CaseBlockNode*> CaseBlockNodeInfo;
 typedef NodeInfo<CaseClauseNode*> CaseClauseNodeInfo;
 typedef NodeInfo<SourceElements*> SourceElementsInfo;
 typedef NodeInfo<ClauseList> ClauseListInfo;
-typedef NodeInfo<VarDeclList> VarDeclListInfo;
+typedef NodeInfo<ExpressionNode*> VarDeclListInfo;
+typedef NodeInfo<ConstDeclList> ConstDeclListInfo;
 
 } // namespace KJS
 
index d1f45c8d472f6cc5c7453d3e41617ea149fe77e3..a9c0f561b640dd855d253b7b833c13702a5f794e 100644 (file)
@@ -70,6 +70,9 @@ static ExpressionNode* makeTypeOfNode(ExpressionNode*);
 static ExpressionNode* makeDeleteNode(ExpressionNode*);
 static ExpressionNode* makeNegateNode(ExpressionNode*);
 static NumberNode* makeNumberNode(double);
+static StatementNode* makeVarStatementNode(ExpressionNode*);
+static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init);
+
 
 #if COMPILER(MSVC)
 
@@ -111,11 +114,21 @@ template <typename T> T mergeDeclarationLists(T decls1, T decls2)
     return decls1;
 }
 
-static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, VarDeclNode* decl)
+static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs)
 {
     if (!varDecls)
         varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>;
-    varDecls->data.append(decl);
+
+    varDecls->data.append(make_pair(ident, attrs));
+
+}
+
+static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl)
+{
+    unsigned attrs = DeclarationStacks::IsConstant;
+    if (decl->init)
+        attrs |= DeclarationStacks::HasInitializer;        
+    appendToVarDeclarationList(varDecls, decl->ident, attrs);
 }
 
 %}
@@ -131,11 +144,10 @@ static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::V
     FuncDeclNode*       funcDeclNode;
     PropertyNode*       propertyNode;
     ArgumentsNode*      argumentsNode;
-    VarDeclNode*        varDeclNode;
+    ConstDeclNode*      constDeclNode;
     CaseBlockNodeInfo   caseBlockNode;
     CaseClauseNodeInfo  caseClauseNode;
     FuncExprNode*       funcExprNode;
-    AssignExprNode*     assignExprNode;
 
     // statement nodes
     StatementNodeInfo   statementNode;
@@ -146,6 +158,7 @@ static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::V
     PropertyList        propertyList;
     ArgumentList        argumentList;
     VarDeclListInfo     varDeclList;
+    ConstDeclListInfo   constDeclList;
     ClauseListInfo      clauseList;
     ElementList         elementList;
     ParameterList       parameterList;
@@ -228,7 +241,7 @@ static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::V
 %type <statementNode>   DebuggerStatement
 %type <statementNode>   SourceElement
 
-%type <assignExprNode>  Initializer InitializerNoIn
+%type <expressionNode>  Initializer InitializerNoIn
 %type <funcDeclNode>    FunctionDeclaration
 %type <funcExprNode>    FunctionExpr
 %type <functionBodyNode>  FunctionBody
@@ -237,8 +250,9 @@ static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::V
 %type <op>              AssignmentOperator
 %type <argumentsNode>   Arguments
 %type <argumentList>    ArgumentList
-%type <varDeclList>     VariableDeclarationList VariableDeclarationListNoIn ConstDeclarationList
-%type <varDeclNode>     VariableDeclaration VariableDeclarationNoIn ConstDeclaration
+%type <varDeclList>     VariableDeclarationList VariableDeclarationListNoIn
+%type <constDeclList>   ConstDeclarationList
+%type <constDeclNode>   ConstDeclaration
 %type <caseBlockNode>   CaseBlock
 %type <caseClauseNode>  CaseClause DefaultClause
 %type <clauseList>      CaseClauses CaseClausesOpt
@@ -703,60 +717,68 @@ Block:
 ;
 
 VariableStatement:
-    VAR VariableDeclarationList ';'     { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+    VAR VariableDeclarationList ';'     { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
                                           DBG($$.m_node, @1, @3); }
-  | VAR VariableDeclarationList error   { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+  | VAR VariableDeclarationList error   { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
                                           DBG($$.m_node, @1, @2);
                                           AUTO_SEMICOLON; }
 ;
 
 VariableDeclarationList:
-    VariableDeclaration                 { $$.m_node.head = $1;
-                                          $$.m_node.tail = $$.m_node.head;
+    IDENT                               { $$.m_node = 0;
                                           $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
-                                          $$.m_varDeclarations->data.append($1);
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
                                           $$.m_funcDeclarations = 0;
                                         }
-  | VariableDeclarationList ',' VariableDeclaration
-                                        { $$.m_node.head = $1.m_node.head;
-                                          $1.m_node.tail->next = $3;
-                                          $$.m_node.tail = $3;
+  | IDENT Initializer                   { $$.m_node = new AssignResolveNode(*$1, $2);
+                                          $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+                                          $$.m_funcDeclarations = 0;
+                                        }
+  | VariableDeclarationList ',' IDENT
+                                        { $$.m_node = $1.m_node;
+                                          $$.m_varDeclarations = $1.m_varDeclarations;
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+                                          $$.m_funcDeclarations = 0;
+                                        }
+  | VariableDeclarationList ',' IDENT Initializer
+                                        { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
                                           $$.m_varDeclarations = $1.m_varDeclarations;
-                                          $$.m_varDeclarations->data.append($3);
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
                                           $$.m_funcDeclarations = 0;
                                         }
 ;
 
 VariableDeclarationListNoIn:
-    VariableDeclarationNoIn             { $$.m_node.head = $1; 
-                                          $$.m_node.tail = $$.m_node.head;
+    IDENT                               { $$.m_node = 0;
                                           $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
-                                          $$.m_varDeclarations->data.append($1);
-                                          $$.m_funcDeclarations = 0; }
-  | VariableDeclarationListNoIn ',' VariableDeclarationNoIn
-                                        { $$.m_node.head = $1.m_node.head;
-                                          $1.m_node.tail->next = $3;
-                                          $$.m_node.tail = $3; 
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
+                                          $$.m_funcDeclarations = 0;
+                                        }
+  | IDENT InitializerNoIn               { $$.m_node = new AssignResolveNode(*$1, $2);
+                                          $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+                                          $$.m_funcDeclarations = 0;
+                                        }
+  | VariableDeclarationListNoIn ',' IDENT
+                                        { $$.m_node = $1.m_node;
                                           $$.m_varDeclarations = $1.m_varDeclarations;
-                                          $$.m_varDeclarations->data.append($3);
-                                          $$.m_funcDeclarations = 0; }
-;
-
-VariableDeclaration:
-    IDENT                               { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
-  | IDENT Initializer                   { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
-;
-
-VariableDeclarationNoIn:
-    IDENT                               { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
-  | IDENT InitializerNoIn               { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+                                          $$.m_funcDeclarations = 0;
+                                        }
+  | VariableDeclarationListNoIn ',' IDENT InitializerNoIn
+                                        { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
+                                          $$.m_varDeclarations = $1.m_varDeclarations;
+                                          appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
+                                          $$.m_funcDeclarations = 0;
+                                        }
 ;
 
 ConstStatement:
-    CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+    CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
                                           DBG($$.m_node, @1, @3); }
   | CONSTTOKEN ConstDeclarationList error
-                                        { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+                                        { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
                                           DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
@@ -764,28 +786,28 @@ ConstDeclarationList:
     ConstDeclaration                    { $$.m_node.head = $1;
                                           $$.m_node.tail = $$.m_node.head;
                                           $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
-                                          $$.m_varDeclarations->data.append($1);
+                                          appendToVarDeclarationList($$.m_varDeclarations, $1);
                                           $$.m_funcDeclarations = 0; }
   | ConstDeclarationList ',' ConstDeclaration
                                         {  $$.m_node.head = $1.m_node.head;
                                           $1.m_node.tail->next = $3;
                                           $$.m_node.tail = $3;
                                           $$.m_varDeclarations = $1.m_varDeclarations;
-                                          $$.m_varDeclarations->data.append($3);
+                                          appendToVarDeclarationList($$.m_varDeclarations, $3);
                                           $$.m_funcDeclarations = 0; }
 ;
 
 ConstDeclaration:
-    IDENT                               { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Constant); }
-  | IDENT Initializer                   { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Constant); }
+    IDENT                               { $$ = new ConstDeclNode(*$1, 0); }
+  | IDENT Initializer                   { $$ = new ConstDeclNode(*$1, $2); }
 ;
 
 Initializer:
-    '=' AssignmentExpr                  { $$ = new AssignExprNode($2); }
+    '=' AssignmentExpr                  { $$ = $2; }
 ;
 
 InitializerNoIn:
-    '=' AssignmentExprNoIn              { $$ = new AssignExprNode($2); }
+    '=' AssignmentExprNoIn              { $$ = $2; }
 ;
 
 EmptyStatement:
@@ -816,11 +838,11 @@ IterationStatement:
   | WHILE '(' Expr ')' Statement        { $$ = createNodeInfo<StatementNode*>(new WhileNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
                                           DBG($$.m_node, @1, @4); }
   | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement
-                                        { $$ = createNodeInfo<StatementNode*>(new ForNode($3, $5, $7, $9.m_node), $9.m_varDeclarations, $9.m_funcDeclarations);
+                                        { $$ = createNodeInfo<StatementNode*>(new ForNode($3, $5, $7, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations);
                                           DBG($$.m_node, @1, @8); 
                                         }
   | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
-                                        { $$ = createNodeInfo<StatementNode*>(new ForNode($4.m_node.head, $6, $8, $10.m_node),
+                                                                            { $$ = createNodeInfo<StatementNode*>(new ForNode($4.m_node, $6, $8, $10.m_node, true),
                                                                               mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations),
                                                                               mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations));
                                           DBG($$.m_node, @1, @9); }
@@ -834,12 +856,12 @@ IterationStatement:
                                         }
   | FOR '(' VAR IDENT INTOKEN Expr ')' Statement
                                         { ForInNode *forIn = new ForInNode(*$4, 0, $6, $8.m_node);
-                                          appendToVarDeclarationList($8.m_varDeclarations, forIn->getVarDecl());
+                                          appendToVarDeclarationList($8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
                                           $$ = createNodeInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations);
                                           DBG($$.m_node, @1, @7); }
   | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
                                         { ForInNode *forIn = new ForInNode(*$4, $5, $7, $9.m_node);
-                                          appendToVarDeclarationList($9.m_varDeclarations, forIn->getVarDecl());
+                                          appendToVarDeclarationList($9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
                                           $$ = createNodeInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations);
                                           DBG($$.m_node, @1, @8); }
 ;
@@ -980,7 +1002,7 @@ FormalParameterList:
 FunctionBody:
     /* not in spec */           { $$ = new FunctionBodyNode(0, 0, 0); }
   | SourceElements              { $$ = new FunctionBodyNode($1.m_node, $1.m_varDeclarations ? &$1.m_varDeclarations->data : 0, 
-                                                                                  $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0);
+                                                            $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0);
                                   // As in mergeDeclarationLists() we have to ref/deref to safely get rid of
                                   // the declaration lists.
                                   if ($1.m_varDeclarations) {
@@ -1218,3 +1240,21 @@ static bool allowAutomaticSemicolon()
 {
     return yychar == '}' || yychar == 0 || lexer().prevTerminator();
 }
+
+static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init)
+{
+    if (!list)
+        return init;
+    return new CommaNode(list, init);
+}
+
+// We turn variable declarations into either assignments or empty
+// statements (which later get stripped out), because the actual
+// declaration work is hoisted up to the start of the function body
+static StatementNode* makeVarStatementNode(ExpressionNode* expr)
+{
+    if (!expr)
+        return new EmptyStatementNode();
+    return new VarStatementNode(expr);
+}
+
index 8a63441a70265c23d2edfa0fc4937f12ae53eef5..d805155457f6e91b456fcc0f6c2651b531c9b695 100644 (file)
@@ -380,6 +380,9 @@ void StatementNode::setLoc(int firstLine, int lastLine)
 
 void SourceElements::append(PassRefPtr<StatementNode> statement)
 {
+    if (statement->isEmptyStatement())
+        return;
+
     if (Debugger::debuggersPresent)
         m_statements.append(new BreakpointCheckStatement(statement));
     else
@@ -3419,49 +3422,15 @@ JSValue* CommaNode::evaluate(ExecState *exec)
     return expr2->evaluate(exec);
 }
 
-// ------------------------------ AssignExprNode -------------------------------
-
-void AssignExprNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
-{
-    nodeStack.append(expr.get());
-}
+// ------------------------------ ConstDeclNode ----------------------------------
 
-// ECMA 12.2
-JSValue* AssignExprNode::evaluate(ExecState* exec)
-{
-    return expr->evaluate(exec);
-}
-
-bool AssignExprNode::evaluateToBoolean(ExecState* exec)
-{
-    return expr->evaluateToBoolean(exec);
-}
-
-double AssignExprNode::evaluateToNumber(ExecState* exec)
-{
-    return expr->evaluateToNumber(exec);
-}
-
-int32_t AssignExprNode::evaluateToInt32(ExecState* exec)
-{
-    return expr->evaluateToInt32(exec);
-}
-
-uint32_t AssignExprNode::evaluateToUInt32(ExecState* exec)
-{
-    return expr->evaluateToInt32(exec);
-}
-
-// ------------------------------ VarDeclNode ----------------------------------
-
-VarDeclNode::VarDeclNode(const Identifier &id, AssignExprNode *in, Type t)
-    : varType(t)
-    , ident(id)
+ConstDeclNode::ConstDeclNode(const Identifier& id, ExpressionNode* in)
+    : ident(id)
     , init(in)
 {
 }
 
-void VarDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConstDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
 {
     if (next)
         nodeStack.append(next.get());
@@ -3469,7 +3438,7 @@ void VarDeclNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeSt
         nodeStack.append(init.get());
 }
 
-void VarDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
+void ConstDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
 {
     ScopeChainIterator iter = chain.begin();
     ScopeChainIterator end = chain.end();
@@ -3490,14 +3459,13 @@ void VarDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSVal
     
     unsigned flags = 0;
     base->getPropertyAttributes(ident, flags);
-    if (varType == VarDeclNode::Constant)
-        flags |= ReadOnly;
+    flags |= ReadOnly;
     
     base->put(exec, ident, val, flags);
 }
 
 // ECMA 12.2
-inline void VarDeclNode::evaluateSingle(ExecState* exec)
+inline void ConstDeclNode::evaluateSingle(ExecState* exec)
 {
     ASSERT(exec->variableObject()->hasOwnProperty(exec, ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
     const ScopeChain& chain = exec->scopeChain();
@@ -3513,8 +3481,7 @@ inline void VarDeclNode::evaluateSingle(ExecState* exec)
             int flags = Internal;
             if (exec->codeType() != EvalCode)
                 flags |= DontDelete;
-            if (varType == VarDeclNode::Constant)
-                flags |= ReadOnly;
+            flags |= ReadOnly;
             variableObject->put(exec, ident, val, flags);
         } else {
             JSValue* val = init->evaluate(exec);
@@ -3528,19 +3495,18 @@ inline void VarDeclNode::evaluateSingle(ExecState* exec)
 
             unsigned flags = 0;
             variableObject->getPropertyAttributes(ident, flags);
-            if (varType == VarDeclNode::Constant)
-                flags |= ReadOnly;
+            flags |= ReadOnly;
             
             variableObject->put(exec, ident, val, flags);
         }
     }
 }
 
-JSValue* VarDeclNode::evaluate(ExecState* exec)
+JSValue* ConstDeclNode::evaluate(ExecState* exec)
 {
     evaluateSingle(exec);
 
-    if (VarDeclNode* n = next.get()) {
+    if (ConstDeclNode* n = next.get()) {
         do {
             n->evaluateSingle(exec);
             KJS_CHECKEXCEPTIONVALUE
@@ -3550,16 +3516,16 @@ JSValue* VarDeclNode::evaluate(ExecState* exec)
     return jsUndefined();
 }
 
-// ------------------------------ VarStatementNode -----------------------------
+// ------------------------------ ConstStatementNode -----------------------------
 
-void VarStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+void ConstStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
 {
     ASSERT(next);
     nodeStack.append(next.get());
 }
 
 // ECMA 12.2
-JSValue* VarStatementNode::execute(ExecState* exec)
+JSValue* ConstStatementNode::execute(ExecState* exec)
 {
     next->evaluate(exec);
     KJS_CHECKEXCEPTION
@@ -3654,6 +3620,22 @@ JSValue* ExprStatementNode::execute(ExecState* exec)
     return exec->setNormalCompletion(value);
 }
 
+// ------------------------------ VarStatementNode ----------------------------
+
+void VarStatementNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
+{
+    ASSERT(expr);
+    nodeStack.append(expr.get());
+}
+
+JSValue* VarStatementNode::execute(ExecState* exec)
+{
+    expr->evaluate(exec);
+    KJS_CHECKEXCEPTION
+
+    return exec->setNormalCompletion();
+}
+
 // ------------------------------ IfNode ---------------------------------------
 
 void IfNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
@@ -3826,16 +3808,16 @@ continueForLoop:
 // ------------------------------ ForInNode ------------------------------------
 
 ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* e, StatementNode* s)
-  : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
+    : init(0L), lexpr(l), expr(e), statement(s), identIsVarDecl(false)
 {
 }
 
-ForInNode::ForInNode(const Identifier& i, AssignExprNode* in, ExpressionNode* e, StatementNode* s)
-  : ident(i), init(in), expr(e), statement(s)
+ForInNode::ForInNode(const Identifier& i, ExpressionNode* in, ExpressionNode* e, StatementNode* s)
+    : ident(i), lexpr(new ResolveNode(i)), expr(e), statement(s), identIsVarDecl(true)
 {
+  if (in)
+      init = new AssignResolveNode(i, in);
   // for( var foo = bar in baz )
-  varDecl = new VarDeclNode(ident, init.get(), VarDeclNode::Variable);
-  lexpr = new ResolveNode(ident);
 }
 
 void ForInNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack& nodeStack)
@@ -3843,8 +3825,8 @@ void ForInNode::optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStac
     nodeStack.append(statement.get());
     nodeStack.append(expr.get());
     nodeStack.append(lexpr.get());
-    if (varDecl)
-        nodeStack.append(varDecl.get());
+    if (init)
+        nodeStack.append(init.get());
 }
 
 // ECMA 12.6.4
@@ -3852,8 +3834,8 @@ JSValue* ForInNode::execute(ExecState* exec)
 {
   JSValue* value = 0;
 
-  if (varDecl) {
-    varDecl->evaluate(exec);
+  if (init) {
+    init->evaluate(exec);
     KJS_CHECKEXCEPTION
   }
 
@@ -4267,7 +4249,7 @@ void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
     }
 
     for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
-        Identifier& ident = m_varStack[i]->ident;
+        Identifier& ident = m_varStack[i].first;
         if (ident == exec->propertyNames().arguments)
             continue;
         symbolTable.add(ident.ustring().rep(), localStorageIndex);
@@ -4301,7 +4283,7 @@ void ProgramNode::initializeSymbolTable(ExecState* exec)
     size = m_varStack.size();
     m_varIndexes.resize(size);
     for (size_t i = 0; i < size; ++i) {
-        const Identifier& ident = m_varStack[i]->ident;
+        const Identifier& ident = m_varStack[i].first;
         if (variableObject->getDirect(ident)) {
             m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
             continue;
@@ -4368,9 +4350,9 @@ void FunctionBodyNode::processDeclarations(ExecState* exec)
     }
 
     for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
-        VarDeclNode* node = m_varStack[i];
+        bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
         int attributes = minAttributes;
-        if (node->varType == VarDeclNode::Constant)
+        if (isConstant)
             attributes |= ReadOnly;
         localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
     }
@@ -4420,9 +4402,9 @@ void ProgramNode::processDeclarations(ExecState* exec)
         if (index == missingSymbolMarker())
             continue;
 
-        VarDeclNode* node = m_varStack[i];
+        bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
         int attributes = minAttributes;
-        if (node->varType == VarDeclNode::Constant)
+        if (isConstant)
             attributes |= ReadOnly;
         LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
             
@@ -4443,13 +4425,14 @@ void EvalNode::processDeclarations(ExecState* exec)
     int minAttributes = Internal;
 
     for (i = 0, size = m_varStack.size(); i < size; ++i) {
-        VarDeclNode* node = m_varStack[i];
-        if (variableObject->hasOwnProperty(exec, node->ident))
+        Identifier& ident = m_varStack[i].first;
+        bool isConstant = m_varStack[i].second & DeclarationStacks::IsConstant;
+        if (variableObject->hasOwnProperty(exec, ident))
             continue;
         int attributes = minAttributes;
-        if (node->varType == VarDeclNode::Constant)
+        if (isConstant)
             attributes |= ReadOnly;
-        variableObject->put(exec, node->ident, jsUndefined(), attributes);
+        variableObject->put(exec, ident, jsUndefined(), attributes);
     }
 
     for (i = 0, size = m_functionStack.size(); i < size; ++i) {
index da09eb2b401a7b13471593b12ab25dba815cc07f..233737672c1d2509ba88c0c00e606721e837768f 100644 (file)
@@ -45,7 +45,7 @@ namespace KJS {
     class Node;
     class PropertyListNode;
     class SourceStream;
-    class VarDeclNode;
+    class ConstDeclNode;
 
     enum Operator {
         OpEqual,
@@ -88,7 +88,8 @@ namespace KJS {
   
   struct DeclarationStacks {
       typedef Vector<Node*, 16> NodeStack;
-      typedef Vector<VarDeclNode*, 16> VarStack;
+      enum { IsConstant, HasInitializer } VarAttrs;
+      typedef Vector<std::pair<Identifier, unsigned>, 16> VarStack;
       typedef Vector<FuncDeclNode*, 16> FunctionStack;
       
       DeclarationStacks(ExecState* e, NodeStack& n, VarStack& v, FunctionStack& f)
@@ -201,6 +202,7 @@ namespace KJS {
     virtual JSValue* execute(ExecState *exec) KJS_FAST_CALL = 0;
     void pushLabel(const Identifier &id) KJS_FAST_CALL { ls.push(id); }
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+    virtual bool isEmptyStatement() const KJS_FAST_CALL { return false; }
   protected:
     LabelStack ls;
   private:
@@ -1683,48 +1685,31 @@ namespace KJS {
     RefPtr<ExpressionNode> expr2;
   };
 
-    class AssignExprNode : public ExpressionNode {
+  class ConstDeclNode : public ExpressionNode {
   public:
-    AssignExprNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) {}
-    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
-    virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
-    virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
-    virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
-    virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
-    virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
-    virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-    virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
-  private:
-    RefPtr<ExpressionNode> expr;
-  };
-
-    class VarDeclNode : public ExpressionNode {
-  public:
-    enum Type { Variable, Constant };
-    VarDeclNode(const Identifier &id, AssignExprNode *in, Type t) KJS_FAST_CALL;
+    ConstDeclNode(const Identifier& id, ExpressionNode* in) KJS_FAST_CALL;
     virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
     virtual KJS::JSValue* evaluate(ExecState*) KJS_FAST_CALL;
     void evaluateSingle(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
-    PassRefPtr<VarDeclNode> releaseNext() KJS_FAST_CALL { return next.release(); }
+    PassRefPtr<ConstDeclNode> releaseNext() KJS_FAST_CALL { return next.release(); }
 
-    Type varType;
     Identifier ident;
-    ListRefPtr<VarDeclNode> next;
+    ListRefPtr<ConstDeclNode> next;
+    RefPtr<ExpressionNode> init;
   private:
     void handleSlowCase(ExecState*, const ScopeChain&, JSValue*) KJS_FAST_CALL NEVER_INLINE;
-    RefPtr<AssignExprNode> init;
   };
 
-  class VarStatementNode : public StatementNode {
+  class ConstStatementNode : public StatementNode {
   public:
-    VarStatementNode(VarDeclNode* l) KJS_FAST_CALL : next(l) { }
+    ConstStatementNode(ConstDeclNode* l) KJS_FAST_CALL : next(l) { }
     virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
   private:
-    RefPtr<VarDeclNode> next;
+    RefPtr<ConstDeclNode> next;
   };
 
   typedef Vector<RefPtr<StatementNode> > StatementVector;
@@ -1756,6 +1741,7 @@ namespace KJS {
     EmptyStatementNode() KJS_FAST_CALL { } // debug
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+    virtual bool isEmptyStatement() const KJS_FAST_CALL { return true; }
   };
 
   class ExprStatementNode : public StatementNode {
@@ -1768,6 +1754,16 @@ namespace KJS {
     RefPtr<ExpressionNode> expr;
   };
 
+  class VarStatementNode : public StatementNode {
+  public:
+    VarStatementNode(ExpressionNode* e) KJS_FAST_CALL : expr(e) { }
+    virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
+    virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+    virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+  private:
+    RefPtr<ExpressionNode> expr;
+  };
+
   class IfNode : public StatementNode {
   public:
     IfNode(ExpressionNode* e, StatementNode *s) KJS_FAST_CALL
@@ -1815,11 +1811,12 @@ namespace KJS {
 
   class ForNode : public StatementNode {
   public:
-    ForNode(ExpressionNode* e1, ExpressionNode* e2, ExpressionNode* e3, StatementNode* s) KJS_FAST_CALL
+      ForNode(ExpressionNode* e1, ExpressionNode* e2, ExpressionNode* e3, StatementNode* s, bool e1WasVarDecl) KJS_FAST_CALL
         : expr1(e1 ? e1 : new TrueNode)
         , expr2(e2 ? e2 : new TrueNode)
         , expr3(e3 ? e3 : new TrueNode)
         , statement(s)
+        , expr1WasVarDecl(e1WasVarDecl)
     {
         ASSERT(expr1);
         ASSERT(expr2);
@@ -1838,23 +1835,23 @@ namespace KJS {
     RefPtr<ExpressionNode> expr2;
     RefPtr<ExpressionNode> expr3;
     RefPtr<StatementNode> statement;
+    bool expr1WasVarDecl;
   };
 
   class ForInNode : public StatementNode {
   public:
     ForInNode(ExpressionNode*  l, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
-    ForInNode(const Identifier &i, AssignExprNode *in, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
+    ForInNode(const Identifier &i, ExpressionNode *in, ExpressionNode* e, StatementNode *s) KJS_FAST_CALL;
     virtual void optimizeVariableAccess(SymbolTable&, DeclarationStacks::NodeStack&) KJS_FAST_CALL;
     virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
-    VarDeclNode* getVarDecl() { return varDecl.get(); }
   private:
     Identifier ident;
-    RefPtr<AssignExprNode> init;
+    RefPtr<ExpressionNode> init;
     RefPtr<ExpressionNode> lexpr;
     RefPtr<ExpressionNode> expr;
-    RefPtr<VarDeclNode> varDecl;
     RefPtr<StatementNode> statement;
+    bool identIsVarDecl;
   };
 
   class ContinueNode : public StatementNode {
@@ -1956,6 +1953,7 @@ namespace KJS {
 
     int sourceId() const KJS_FAST_CALL { return m_sourceId; }
     const UString& sourceURL() const KJS_FAST_CALL { return m_sourceURL; }
+    virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
 
   protected:
     void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
@@ -2124,9 +2122,9 @@ namespace KJS {
       ArgumentListNode* tail;
   };
 
-  struct VarDeclList {
-      VarDeclNode* head;
-      VarDeclNode* tail;
+  struct ConstDeclList {
+      ConstDeclNode* head;
+      ConstDeclNode* tail;
   };
 
   struct ParameterList {
index d4f00636c2c7466be7c88629d4f6f6c003d85925..577ea6955e3cc75a1eb47b577367c609db15c2ea 100644 (file)
@@ -707,21 +707,21 @@ void CommaNode::streamTo(SourceStream& s) const
     s << PrecAssignment << expr1 << ", " << PrecAssignment << expr2;
 }
 
-void AssignExprNode::streamTo(SourceStream& s) const
+void ConstDeclNode::streamTo(SourceStream& s) const
 {
-    s << " = " << PrecAssignment << expr;
-}
-
-void VarDeclNode::streamTo(SourceStream& s) const
-{
-    s << "var " << ident << init;
-    for (VarDeclNode* n = next.get(); n; n = n->next.get())
-        s << ", " << ident << init;
+    s << ident;
+    if (init)
+        s << " = " << init;
+    for (ConstDeclNode* n = next.get(); n; n = n->next.get()) {
+        s << ", " << ident;
+        if (init)
+            s << " = " << init;
+    }
 }
 
-void VarStatementNode::streamTo(SourceStream& s) const
+void ConstStatementNode::streamTo(SourceStream& s) const
 {
-    s << Endl << next << ';';
+    s << Endl << "const " << next << ';';
 }
 
 static inline void statementListStreamTo(const Vector<RefPtr<StatementNode> >& nodes, SourceStream& s)
@@ -737,6 +737,28 @@ void BlockNode::streamTo(SourceStream& s) const
     s << Unindent << Endl << "}";
 }
 
+void ScopeNode::streamTo(SourceStream& s) const
+{
+    s << Endl << "{" << Indent;
+
+    bool printedVar = false;
+    for (size_t i = 0; i < m_varStack.size(); ++i) {
+        if (m_varStack[i].second == 0) {
+            if (!printedVar) {
+                s << Endl << "var ";
+                printedVar = true;
+            } else
+                s << ", ";
+            s << m_varStack[i].first;
+        }
+    }
+    if (printedVar)
+        s << ';';
+
+    statementListStreamTo(m_children, s); 
+    s << Unindent << Endl << "}";
+}
+
 void EmptyStatementNode::streamTo(SourceStream& s) const
 {
     s << Endl << ';';
@@ -747,6 +769,11 @@ void ExprStatementNode::streamTo(SourceStream& s) const
     s << Endl << expr << ';';
 }
 
+void VarStatementNode::streamTo(SourceStream& s) const
+{
+    s << Endl << "var " << expr << ';';
+}
+
 void IfNode::streamTo(SourceStream& s) const
 {
     s << Endl << "if (" << m_condition << ')' << Indent << m_ifBlock << Unindent;
@@ -772,6 +799,7 @@ void WhileNode::streamTo(SourceStream& s) const
 void ForNode::streamTo(SourceStream& s) const
 {
     s << Endl << "for ("
+        << (expr1WasVarDecl ? "var " : "")
         << expr1
         << "; " << expr2
         << "; " << expr3
@@ -781,9 +809,13 @@ void ForNode::streamTo(SourceStream& s) const
 void ForInNode::streamTo(SourceStream& s) const
 {
     s << Endl << "for (";
-    if (varDecl)
-        s << varDecl;
-    else
+    if (identIsVarDecl) {
+        s << "var ";
+        if (init)
+            s << init;
+        else
+            s << PrecLeftHandSide << lexpr;
+    } else
         s << PrecLeftHandSide << lexpr;
 
     s << " in " << expr << ')' << Indent << statement << Unindent;