Replace post-parse pass to find declarations with logic in the parser itself
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Dec 2007 07:42:29 +0000 (07:42 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Dec 2007 07:42:29 +0000 (07:42 +0000)
Reviewed by Geoff.

Instead of finding declarations in a pass following the initial parsing of
a program, we incorporate the logic directly into the parser.  This lays
the groundwork for further optimisations (such as improving performance in
declaration expressions -- var x = y; -- to match that of standard assignment)
in addition to providing a 0.4% performance improvement in SunSpider.

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

JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/kjs/Parser.cpp
JavaScriptCore/kjs/Parser.h
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h

index 3b84312..c004cdf 100644 (file)
@@ -1,3 +1,41 @@
+2007-12-18  Oliver Hunt  <oliver@apple.com>
+
+        Replace post-parse pass to find declarations with logic in the parser itself
+
+        Reviewed by Geoff.
+
+        Instead of finding declarations in a pass following the initial parsing of
+        a program, we incorporate the logic directly into the parser.  This lays
+        the groundwork for further optimisations (such as improving performance in
+        declaration expressions -- var x = y; -- to match that of standard assignment)
+        in addition to providing a 0.4% performance improvement in SunSpider.
+
+        * JavaScriptCore.exp:
+        * kjs/Parser.cpp:
+        (KJS::Parser::parse):
+        * kjs/Parser.h:
+        (KJS::Parser::didFinishParsing):
+        (KJS::Parser::parse):
+        * kjs/grammar.y:
+        * kjs/nodes.cpp:
+        (KJS::ParserTracked::ParserTracked):
+        (KJS::ParserTracked::~ParserTracked):
+        (KJS::ParserTracked::ref):
+        (KJS::ParserTracked::deref):
+        (KJS::ParserTracked::refcount):
+        (KJS::ParserTracked::clearNewTrackedObjects):
+        (KJS::Node::Node):
+        (KJS::ScopeNode::ScopeNode):
+        (KJS::ProgramNode::ProgramNode):
+        (KJS::EvalNode::EvalNode):
+        (KJS::FunctionBodyNode::FunctionBodyNode):
+        (KJS::FunctionBodyNode::initializeSymbolTable):
+        (KJS::FunctionBodyNode::processDeclarations):
+        * kjs/nodes.h:
+        (KJS::ParserTracked::):
+        (KJS::Node::):
+        (KJS::ScopeNode::):
+
 2007-12-18  Xan Lopez  <xan@gnome.org>
 
         Reviewed by Geoff.
index 1fd3d9c..e3129ba 100644 (file)
@@ -120,7 +120,7 @@ __ZN3KJS11Interpreter8evaluateEPNS_9ExecStateERKNS_7UStringEiS5_PNS_7JSValueE
 __ZN3KJS11JSImmediate4typeEPKNS_7JSValueE
 __ZN3KJS11JSImmediate8toObjectEPKNS_7JSValueEPNS_9ExecStateE
 __ZN3KJS11JSImmediate8toStringEPKNS_7JSValueE
-__ZN3KJS11ProgramNodeC1EPN3WTF6VectorINS1_6RefPtrINS_13StatementNodeEEELm0EEE
+__ZN3KJS11ProgramNodeC1EPN3WTF6VectorINS1_6RefPtrINS_13StatementNodeEEELm0EEEPNS2_IPNS_11VarDeclNodeELm16EEEPNS2_IPNS_12FuncDeclNodeELm16EEE
 __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierE
 __ZN3KJS11PropertyMap5clearEv
 __ZN3KJS11PropertyMap7restoreERKNS_15SavedPropertiesE
@@ -153,6 +153,8 @@ __ZN3KJS15SavedPropertiesC1Ev
 __ZN3KJS15SavedPropertiesD1Ev
 __ZN3KJS16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZN3KJS16JSVariableObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
+__ZN3KJS16ParserRefCounted3refEv
+__ZN3KJS16ParserRefCounted5derefEv
 __ZN3KJS16RuntimeObjectImp4infoE
 __ZN3KJS16RuntimeObjectImpC1EPNS_8Bindings8InstanceE
 __ZN3KJS17PropertyNameArray3addERKNS_10IdentifierE
@@ -160,8 +162,6 @@ __ZN3KJS19InternalFunctionImp4infoE
 __ZN3KJS19InternalFunctionImpC2EPNS_17FunctionPrototypeERKNS_10IdentifierE
 __ZN3KJS4List15expandAndAppendEPNS_7JSValueE
 __ZN3KJS4List7markSetEv
-__ZN3KJS4Node3refEv
-__ZN3KJS4Node5derefEv
 __ZN3KJS6JSCell9getObjectEv
 __ZN3KJS6JSCellnwEm
 __ZN3KJS6JSLock12DropAllLocksC1Ev
@@ -201,7 +201,6 @@ __ZN3KJS8Debugger6attachEPNS_14JSGlobalObjectE
 __ZN3KJS8Debugger9exceptionEPNS_9ExecStateEiiPNS_7JSValueE
 __ZN3KJS8DebuggerC2Ev
 __ZN3KJS8DebuggerD2Ev
-__ZN3KJS8EvalNodeC1EPN3WTF6VectorINS1_6RefPtrINS_13StatementNodeEEELm0EEE
 __ZN3KJS8JSObject11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
 __ZN3KJS8JSObject12removeDirectERKNS_10IdentifierE
 __ZN3KJS8JSObject14callAsFunctionEPNS_9ExecStateEPS0_RKNS_4ListE
index db663e5..15b498a 100644 (file)
@@ -60,7 +60,7 @@ void Parser::parse(int startingLineNumber,
     bool lexError = lexer.sawError();
     lexer.clear();
 
-    Node::clearNewNodes();
+    ParserRefCounted::deleteNewObjects();
 
     if (parseError || lexError) {
         if (errLine)
index 40f218a..f2e9742 100644 (file)
@@ -28,6 +28,7 @@
 #include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
 #include "nodes.h"
 
 namespace KJS {
@@ -38,6 +39,10 @@ namespace KJS {
 
     struct UChar;
 
+    template <typename T> struct ParserRefCountedData : ParserRefCounted {
+        T data;
+    };
+
     class Parser : Noncopyable {
     public:
         template <class ParsedNode>
@@ -48,9 +53,12 @@ namespace KJS {
         UString sourceURL() const { return m_sourceURL; }
         int sourceId() const { return m_sourceId; }
 
-        void didFinishParsing(SourceElements* sourceElements, int lastLine)
+        void didFinishParsing(SourceElements* sourceElements, ParserRefCountedData<DeclarationStacks::VarStack>* varStack, 
+                              ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, int lastLine)
         {
             m_sourceElements.set(sourceElements);
+            m_varDeclarations = varStack;
+            m_funcDeclarations = funcStack;
             m_lastLine = lastLine;
         }
 
@@ -64,6 +72,8 @@ namespace KJS {
         UString m_sourceURL;
         int m_sourceId;
         OwnPtr<SourceElements> m_sourceElements;
+        RefPtr<ParserRefCountedData<DeclarationStacks::VarStack> > m_varDeclarations;
+        RefPtr<ParserRefCountedData<DeclarationStacks::FunctionStack> > m_funcDeclarations;
         int m_lastLine;
     };
     
@@ -80,7 +90,11 @@ namespace KJS {
             m_sourceURL = UString();
             return 0;
         }
-        RefPtr<ParsedNode> node = new ParsedNode(m_sourceElements.release());
+        RefPtr<ParsedNode> node = new ParsedNode(m_sourceElements.release(), 
+                                                 m_varDeclarations ? &m_varDeclarations->data : 0, 
+                                                 m_funcDeclarations ? &m_funcDeclarations->data : 0);
+        m_varDeclarations = 0;
+        m_funcDeclarations = 0;
         m_sourceURL = UString();
         node->setLoc(startingLineNumber, m_lastLine);
         return node.release();
index 89fba9b..becb2a1 100644 (file)
@@ -84,6 +84,51 @@ static NumberNode* makeNumberNode(double);
 
 #endif
 
+template <typename T> struct NodeInfo {
+    T m_node;
+    ParserRefCountedData<DeclarationStacks::VarStack>* m_varDeclarations;
+    ParserRefCountedData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+};
+
+template <typename T> NodeInfo<T> createNodeInfo(T node, ParserRefCountedData<DeclarationStacks::VarStack>* varDecls, 
+                                                 ParserRefCountedData<DeclarationStacks::FunctionStack>* funcDecls) 
+{
+    NodeInfo<T> result = {node, varDecls, funcDecls};
+    return result;
+}
+
+template <typename T> T mergeDeclarationLists(T decls1, T decls2) 
+{
+    // decls1 or both are null
+    if (!decls1)
+        return decls2;
+    // only decls1 is non-null
+    if (!decls2)
+        return decls1;
+
+    // Both are non-null
+    decls1->data.append(decls2->data);
+    
+    // We manually release the declaration lists to avoid accumulating many many
+    // unused heap allocated vectors
+    decls2->ref();
+    decls2->deref();
+    return decls1;
+}
+
+void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, VarDeclNode* decl)
+{
+    if (!varDecls)
+        varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>;
+    varDecls->data.append(decl);
+}
+
+typedef NodeInfo<StatementNode*> StatementNodeInfo;
+typedef NodeInfo<CaseBlockNode*> CaseBlockNodeInfo;
+typedef NodeInfo<CaseClauseNode*> CaseClauseNodeInfo;
+typedef NodeInfo<SourceElementsStub*> SourceElementsInfo;
+typedef NodeInfo<ClauseList> ClauseListInfo;
+typedef NodeInfo<VarDeclList> VarDeclListInfo;
 %}
 
 %union {
@@ -98,21 +143,21 @@ static NumberNode* makeNumberNode(double);
     PropertyNode*       propertyNode;
     ArgumentsNode*      argumentsNode;
     VarDeclNode*        varDeclNode;
-    CaseBlockNode*      caseBlockNode;
-    CaseClauseNode*     caseClauseNode;
+    CaseBlockNodeInfo   caseBlockNode;
+    CaseClauseNodeInfo  caseClauseNode;
     FuncExprNode*       funcExprNode;
     AssignExprNode*     assignExprNode;
 
     // statement nodes
-    StatementNode*      statementNode;
+    StatementNodeInfo   statementNode;
     FunctionBodyNode*   functionBodyNode;
     ProgramNode*        programNode;
 
-    SourceElementsStub* sourceElements;
+    SourceElementsInfo  sourceElements;
     PropertyList        propertyList;
     ArgumentList        argumentList;
-    VarDeclList         varDeclList;
-    ClauseList          clauseList;
+    VarDeclListInfo     varDeclList;
+    ClauseListInfo      clauseList;
     ElementList         elementList;
     ParameterList       parameterList;
 
@@ -662,31 +707,50 @@ Statement:
 ;
 
 Block:
-    '{' '}'                             { $$ = new BlockNode(new SourceElements); DBG($$, @1, @2); }
-  | '{' SourceElements '}'              { $$ = new BlockNode($2->release()); DBG($$, @1, @3); }
+    '{' '}'                             { $$ = createNodeInfo<StatementNode*>(new BlockNode(new SourceElements), 0, 0);
+                                          DBG($$.m_node, @1, @2); }
+  | '{' SourceElements '}'              { $$ = createNodeInfo<StatementNode*>(new BlockNode($2.m_node->release()), $2.m_varDeclarations, $2.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @3); }
 ;
 
 VariableStatement:
-    VAR VariableDeclarationList ';'     { $$ = new VarStatementNode($2.head); DBG($$, @1, @3); }
-  | VAR VariableDeclarationList error   { $$ = new VarStatementNode($2.head); DBG($$, @1, @2); AUTO_SEMICOLON; }
+    VAR VariableDeclarationList ';'     { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $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);
+                                          DBG($$.m_node, @1, @2);
+                                          AUTO_SEMICOLON; }
 ;
 
 VariableDeclarationList:
-    VariableDeclaration                 { $$.head = $1; 
-                                          $$.tail = $$.head; }
+    VariableDeclaration                 { $$.m_node.head = $1;
+                                          $$.m_node.tail = $$.m_node.head;
+                                          $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+                                          $$.m_varDeclarations->data.append($1);
+                                          $$.m_funcDeclarations = 0;
+                                        }
   | VariableDeclarationList ',' VariableDeclaration
-                                        { $$.head = $1.head;
-                                          $1.tail->next = $3;
-                                          $$.tail = $3; }
+                                        { $$.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);
+                                          $$.m_funcDeclarations = 0;
+                                        }
 ;
 
 VariableDeclarationListNoIn:
-    VariableDeclarationNoIn             { $$.head = $1; 
-                                          $$.tail = $$.head; }
+    VariableDeclarationNoIn             { $$.m_node.head = $1; 
+                                          $$.m_node.tail = $$.m_node.head;
+                                          $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+                                          $$.m_varDeclarations->data.append($1);
+                                          $$.m_funcDeclarations = 0; }
   | VariableDeclarationListNoIn ',' VariableDeclarationNoIn
-                                        { $$.head = $1.head;
-                                          $1.tail->next = $3;
-                                          $$.tail = $3; }
+                                        { $$.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);
+                                          $$.m_funcDeclarations = 0; }
 ;
 
 VariableDeclaration:
@@ -700,18 +764,26 @@ VariableDeclarationNoIn:
 ;
 
 ConstStatement:
-    CONSTTOKEN ConstDeclarationList ';' { $$ = new VarStatementNode($2.head); DBG($$, @1, @3); }
+    CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @3); }
   | CONSTTOKEN ConstDeclarationList error
-                                        { $$ = new VarStatementNode($2.head); DBG($$, @1, @2); AUTO_SEMICOLON; }
+                                        { $$ = createNodeInfo<StatementNode*>(new VarStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 ConstDeclarationList:
-    ConstDeclaration                    { $$.head = $1; 
-                                          $$.tail = $$.head; }
+    ConstDeclaration                    { $$.m_node.head = $1;
+                                          $$.m_node.tail = $$.m_node.head;
+                                          $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+                                          $$.m_varDeclarations->data.append($1);
+                                          $$.m_funcDeclarations = 0; }
   | ConstDeclarationList ',' ConstDeclaration
-                                        { $$.head = $1.head;
-                                          $1.tail->next = $3;
-                                          $$.tail = $3; }
+                                        {  $$.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);
+                                          $$.m_funcDeclarations = 0; }
 ;
 
 ConstDeclaration:
@@ -728,41 +800,59 @@ InitializerNoIn:
 ;
 
 EmptyStatement:
-    ';'                                 { $$ = new EmptyStatementNode(); }
+    ';'                                 { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0); }
 ;
 
 ExprStatement:
-    ExprNoBF ';'                        { $$ = new ExprStatementNode($1); DBG($$, @1, @2); }
-  | ExprNoBF error                      { $$ = new ExprStatementNode($1); DBG($$, @1, @1); AUTO_SEMICOLON; }
+    ExprNoBF ';'                        { $$ = createNodeInfo<StatementNode*>(new ExprStatementNode($1), 0, 0);
+                                          DBG($$.m_node, @1, @2); }
+  | ExprNoBF error                      { $$ = createNodeInfo<StatementNode*>(new ExprStatementNode($1), 0, 0);
+                                          DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
 ;
 
 IfStatement:
     IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE
-                                        { $$ = new IfNode($3, $5, 0); DBG($$, @1, @4); }
+                                        { $$ = createNodeInfo<StatementNode*>(new IfNode($3, $5.m_node, 0), $5.m_varDeclarations, $5.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @4); }
   | IF '(' Expr ')' Statement ELSE Statement
-                                        { $$ = new IfNode($3, $5, $7); DBG($$, @1, @4); }
+                                        { $$ = createNodeInfo<StatementNode*>(new IfNode($3, $5.m_node, $7.m_node), mergeDeclarationLists($5.m_varDeclarations, $7.m_varDeclarations), mergeDeclarationLists($5.m_funcDeclarations, $7.m_funcDeclarations)); 
+                                          DBG($$.m_node, @1, @4); }
 ;
 
 IterationStatement:
-    DO Statement WHILE '(' Expr ')' ';'    { $$ = new DoWhileNode($2, $5); DBG($$, @1, @3); }
-  | DO Statement WHILE '(' Expr ')' error  { $$ = new DoWhileNode($2, $5); DBG($$, @1, @3); } // Always performs automatic semicolon insertion.
-  | WHILE '(' Expr ')' Statement        { $$ = new WhileNode($3, $5); DBG($$, @1, @4); }
+    DO Statement WHILE '(' Expr ')' ';'    { $$ = createNodeInfo<StatementNode*>(new DoWhileNode($2.m_node, $5), $2.m_varDeclarations, $2.m_funcDeclarations);
+                                             DBG($$.m_node, @1, @3); }
+  | DO Statement WHILE '(' Expr ')' error  { $$ = createNodeInfo<StatementNode*>(new DoWhileNode($2.m_node, $5), $2.m_varDeclarations, $2.m_funcDeclarations);
+                                             DBG($$.m_node, @1, @3); } // Always performs automatic semicolon insertion.
+  | 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
-                                        { $$ = new ForNode($3, $5, $7, $9); DBG($$, @1, @8); }
+                                        { $$ = createNodeInfo<StatementNode*>(new ForNode($3, $5, $7, $9.m_node), $9.m_varDeclarations, $9.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @8); 
+                                        }
   | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
-                                        { $$ = new ForNode($4.head, $6, $8, $10); DBG($$, @1, @9); }
+                                        { $$ = createNodeInfo<StatementNode*>(new ForNode($4.m_node.head, $6, $8, $10.m_node),
+                                                                              mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations),
+                                                                              mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations));
+                                          DBG($$.m_node, @1, @9); }
   | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement
                                         {
                                             ExpressionNode* n = $3;
                                             if (!n->isLocation())
                                                 YYABORT;
-                                            $$ = new ForInNode(n, $5, $7);
-                                            DBG($$, @1, @6);
+                                            $$ = createNodeInfo<StatementNode*>(new ForInNode(n, $5, $7.m_node), $7.m_varDeclarations, $7.m_funcDeclarations);
+                                            DBG($$.m_node, @1, @6);
                                         }
   | FOR '(' VAR IDENT INTOKEN Expr ')' Statement
-                                        { $$ = new ForInNode(*$4, 0, $6, $8); DBG($$, @1, @7); }
+                                        { ForInNode *forIn = new ForInNode(*$4, 0, $6, $8.m_node);
+                                          appendToVarDeclarationList($8.m_varDeclarations, forIn->getVarDecl());
+                                          $$ = createNodeInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @7); }
   | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
-                                        { $$ = new ForInNode(*$4, $5, $7, $9); DBG($$, @1, @8); }
+                                        { ForInNode *forIn = new ForInNode(*$4, $5, $7, $9.m_node);
+                                          appendToVarDeclarationList($9.m_varDeclarations, forIn->getVarDecl());
+                                          $$ = createNodeInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @8); }
 ;
 
 ExprOpt:
@@ -776,81 +866,106 @@ ExprNoInOpt:
 ;
 
 ContinueStatement:
-    CONTINUE ';'                        { $$ = new ContinueNode(); DBG($$, @1, @2); }
-  | CONTINUE error                      { $$ = new ContinueNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
-  | CONTINUE IDENT ';'                  { $$ = new ContinueNode(*$2); DBG($$, @1, @3); }
-  | CONTINUE IDENT error                { $$ = new ContinueNode(*$2); DBG($$, @1, @2); AUTO_SEMICOLON; }
+    CONTINUE ';'                        { $$ = createNodeInfo<StatementNode*>(new ContinueNode(), 0, 0);
+                                          DBG($$.m_node, @1, @2); }
+  | CONTINUE error                      { $$ = createNodeInfo<StatementNode*>(new ContinueNode(), 0, 0);
+                                          DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+  | CONTINUE IDENT ';'                  { $$ = createNodeInfo<StatementNode*>(new ContinueNode(*$2), 0, 0);
+                                          DBG($$.m_node, @1, @3); }
+  | CONTINUE IDENT error                { $$ = createNodeInfo<StatementNode*>(new ContinueNode(*$2), 0, 0);
+                                          DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 BreakStatement:
-    BREAK ';'                           { $$ = new BreakNode(); DBG($$, @1, @2); }
-  | BREAK error                         { $$ = new BreakNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
-  | BREAK IDENT ';'                     { $$ = new BreakNode(*$2); DBG($$, @1, @3); }
-  | BREAK IDENT error                   { $$ = new BreakNode(*$2); DBG($$, @1, @2); AUTO_SEMICOLON; }
+    BREAK ';'                           { $$ = createNodeInfo<StatementNode*>(new BreakNode(), 0, 0); DBG($$.m_node, @1, @2); }
+  | BREAK error                         { $$ = createNodeInfo<StatementNode*>(new BreakNode(), 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+  | BREAK IDENT ';'                     { $$ = createNodeInfo<StatementNode*>(new BreakNode(*$2), 0, 0); DBG($$.m_node, @1, @3); }
+  | BREAK IDENT error                   { $$ = createNodeInfo<StatementNode*>(new BreakNode(*$2), 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 ReturnStatement:
-    RETURN ';'                          { $$ = new ReturnNode(0); DBG($$, @1, @2); }
-  | RETURN error                        { $$ = new ReturnNode(0); DBG($$, @1, @1); AUTO_SEMICOLON; }
-  | RETURN Expr ';'                     { $$ = new ReturnNode($2); DBG($$, @1, @3); }
-  | RETURN Expr error                   { $$ = new ReturnNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
+    RETURN ';'                          { $$ = createNodeInfo<StatementNode*>(new ReturnNode(0), 0, 0); DBG($$.m_node, @1, @2); }
+  | RETURN error                        { $$ = createNodeInfo<StatementNode*>(new ReturnNode(0), 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+  | RETURN Expr ';'                     { $$ = createNodeInfo<StatementNode*>(new ReturnNode($2), 0, 0); DBG($$.m_node, @1, @3); }
+  | RETURN Expr error                   { $$ = createNodeInfo<StatementNode*>(new ReturnNode($2), 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 WithStatement:
-    WITH '(' Expr ')' Statement         { $$ = new WithNode($3, $5); DBG($$, @1, @4); }
+    WITH '(' Expr ')' Statement         { $$ = createNodeInfo<StatementNode*>(new WithNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @4); }
 ;
 
 SwitchStatement:
-    SWITCH '(' Expr ')' CaseBlock       { $$ = new SwitchNode($3, $5); DBG($$, @1, @4); }
+    SWITCH '(' Expr ')' CaseBlock       { $$ = createNodeInfo<StatementNode*>(new SwitchNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+                                          DBG($$.m_node, @1, @4); }
 ;
 
 CaseBlock:
-    '{' CaseClausesOpt '}'              { $$ = new CaseBlockNode($2.head, 0, 0); }
+    '{' CaseClausesOpt '}'              { $$ = createNodeInfo<CaseBlockNode*>(new CaseBlockNode($2.m_node.head, 0, 0), $2.m_varDeclarations, $2.m_funcDeclarations); }
   | '{' CaseClausesOpt DefaultClause CaseClausesOpt '}'
-                                        { $$ = new CaseBlockNode($2.head, $3, $4.head); }
+                                        { $$ = createNodeInfo<CaseBlockNode*>(new CaseBlockNode($2.m_node.head, $3.m_node, $4.m_node.head),
+                                                                              mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $3.m_varDeclarations), $4.m_varDeclarations),
+                                                                              mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $3.m_funcDeclarations), $4.m_funcDeclarations)); }
 ;
 
 CaseClausesOpt:
-    /* nothing */                       { $$.head = 0; $$.tail = 0; }
+    /* nothing */                       { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; }
   | CaseClauses
 ;
 
 CaseClauses:
-    CaseClause                          { $$.head = new ClauseListNode($1);
-                                          $$.tail = $$.head; }
-  | CaseClauses CaseClause              { $$.head = $1.head; 
-                                          $$.tail = new ClauseListNode($1.tail, $2); }
+    CaseClause                          { $$.m_node.head = new ClauseListNode($1.m_node);
+                                          $$.m_node.tail = $$.m_node.head;
+                                          $$.m_varDeclarations = $1.m_varDeclarations;
+                                          $$.m_funcDeclarations = $1.m_funcDeclarations; }
+  | CaseClauses CaseClause              { $$.m_node.head = $1.m_node.head;
+                                          $$.m_node.tail = new ClauseListNode($1.m_node.tail, $2.m_node);
+                                          $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations);
+                                          $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations);
+                                        }
 ;
 
 CaseClause:
-    CASE Expr ':'                       { $$ = new CaseClauseNode($2); }
-  | CASE Expr ':' SourceElements        { $$ = new CaseClauseNode($2, $4->release()); }
+    CASE Expr ':'                       { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode($2), 0, 0); }
+  | CASE Expr ':' SourceElements        { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode($2, $4.m_node->release()), $4.m_varDeclarations, $4.m_funcDeclarations); }
 ;
 
 DefaultClause:
-    DEFAULT ':'                         { $$ = new CaseClauseNode(0); }
-  | DEFAULT ':' SourceElements          { $$ = new CaseClauseNode(0, $3->release()); }
+    DEFAULT ':'                         { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode(0), 0, 0); }
+  | DEFAULT ':' SourceElements          { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode(0, $3.m_node->release()), $3.m_varDeclarations, $3.m_funcDeclarations); }
 ;
 
 LabelledStatement:
-    IDENT ':' Statement                 { $3->pushLabel(*$1); $$ = new LabelNode(*$1, $3); }
+    IDENT ':' Statement                 { $3.m_node->pushLabel(*$1);
+                                          $$ = createNodeInfo<StatementNode*>(new LabelNode(*$1, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations); }
 ;
 
 ThrowStatement:
-    THROW Expr ';'                      { $$ = new ThrowNode($2); DBG($$, @1, @3); }
-  | THROW Expr error                    { $$ = new ThrowNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
+    THROW Expr ';'                      { $$ = createNodeInfo<StatementNode*>(new ThrowNode($2), 0, 0); DBG($$.m_node, @1, @3); }
+  | THROW Expr error                    { $$ = createNodeInfo<StatementNode*>(new ThrowNode($2), 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 TryStatement:
-    TRY Block FINALLY Block             { $$ = new TryNode($2, CommonIdentifiers::shared()->nullIdentifier, 0, $4); DBG($$, @1, @2); }
-  | TRY Block CATCH '(' IDENT ')' Block { $$ = new TryNode($2, *$5, $7, 0); DBG($$, @1, @2); }
+    TRY Block FINALLY Block             { $$ = createNodeInfo<StatementNode*>(new TryNode($2.m_node, CommonIdentifiers::shared()->nullIdentifier, 0, $4.m_node),
+                                                                              mergeDeclarationLists($2.m_varDeclarations, $4.m_varDeclarations),
+                                                                              mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations));
+                                          DBG($$.m_node, @1, @2); }
+  | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeInfo<StatementNode*>(new TryNode($2.m_node, *$5, $7.m_node, 0),
+                                                                              mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations),
+                                                                              mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations));
+                                          DBG($$.m_node, @1, @2); }
   | TRY Block CATCH '(' IDENT ')' Block FINALLY Block
-                                        { $$ = new TryNode($2, *$5, $7, $9); DBG($$, @1, @2); }
+                                        { $$ = createNodeInfo<StatementNode*>(new TryNode($2.m_node, *$5, $7.m_node, $9.m_node),
+                                                                              mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), $9.m_varDeclarations),
+                                                                              mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), $9.m_funcDeclarations));
+                                          DBG($$.m_node, @1, @2); }
 ;
 
 DebuggerStatement:
-    DEBUGGER ';'                        { $$ = new EmptyStatementNode(); DBG($$, @1, @2); }
-  | DEBUGGER error                      { $$ = new EmptyStatementNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
+    DEBUGGER ';'                        { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0);
+                                          DBG($$.m_node, @1, @2); }
+  | DEBUGGER error                      { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0);
+                                          DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
 ;
 
 FunctionDeclaration:
@@ -874,22 +989,41 @@ FormalParameterList:
 ;
 
 FunctionBody:
-    /* not in spec */           { $$ = new FunctionBodyNode(new SourceElements); }
-  | SourceElements              { $$ = new FunctionBodyNode($1->release()); }
+    /* not in spec */           { $$ = new FunctionBodyNode(new SourceElements, 0, 0); }
+  | SourceElements              { $$ = new FunctionBodyNode($1.m_node->release(), $1.m_varDeclarations ? &$1.m_varDeclarations->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) {
+                                      $1.m_varDeclarations->ref();
+                                      $1.m_varDeclarations->deref();
+                                  }
+                                  if ($1.m_funcDeclarations) {
+                                      $1.m_funcDeclarations->ref();
+                                      $1.m_funcDeclarations->deref();
+                                  }
+                                }
 ;
 
 Program:
-    /* not in spec */                   { parser().didFinishParsing(new SourceElements, @0.last_line); }
-    | SourceElements                    { parser().didFinishParsing($1->release(), @1.last_line); }
+    /* not in spec */                   { parser().didFinishParsing(new SourceElements, 0, 0, @0.last_line); }
+    | SourceElements                    { parser().didFinishParsing($1.m_node->release(), $1.m_varDeclarations, $1.m_funcDeclarations, @1.last_line); }
 ;
 
 SourceElements:
-    SourceElement                       { $$ = new SourceElementsStub; $$->append($1); }
-  | SourceElements SourceElement        { $$->append($2); }
+    SourceElement                       { $$.m_node = new SourceElementsStub;
+                                          $$.m_node->append($1.m_node);
+                                          $$.m_varDeclarations = $1.m_varDeclarations;
+                                          $$.m_funcDeclarations = $1.m_funcDeclarations;
+                                        }
+  | SourceElements SourceElement        { $$.m_node->append($2.m_node);
+                                          $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations);
+                                          $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations);
+                                        }
 ;
 
 SourceElement:
-    FunctionDeclaration                 { $$ = $1; }
+    FunctionDeclaration                 { $$ = createNodeInfo<StatementNode*>($1, 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>); $$.m_funcDeclarations->data.append($1); }
   | Statement                           { $$ = $1; }
 ;
  
index c37e411..6c1ea9c 100644 (file)
@@ -110,117 +110,116 @@ static inline bool canSkipLookup(ExecState* exec, const Identifier& ident)
 #endif
 static WTFLogChannel LogKJSNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
 
-struct NodeCounter { 
+struct ParserRefCountedCounter { 
     static unsigned count; 
-    ~NodeCounter() 
+    ParserRefCountedCounter() 
     { 
         if (count) 
             LOG(KJSNodeLeaks, "LEAK: %u KJS::Node\n", count); 
     }
 };
-unsigned NodeCounter::count = 0;
-static NodeCounter nodeCounter;
+unsigned ParserRefCountedCounter::count = 0;
+static ParserRefCountedCounter parserRefCountedCounter;
 #endif
 
-static HashSet<Node*>* newNodes;
-static HashCountedSet<Node*>* nodeExtraRefCounts;
+static HashSet<ParserRefCounted*>* newTrackedObjects;
+static HashCountedSet<ParserRefCounted*>* trackedObjectExtraRefCounts;
 
-Node::Node()
-    : m_mayHaveDeclarations(false)
-    , m_expectedReturnType(ObjectType)
-{
-#ifndef NDEBUG
-    ++NodeCounter::count;
-#endif
-  m_line = lexer().lineNo();
-  if (!newNodes)
-      newNodes = new HashSet<Node*>;
-  newNodes->add(this);
-}
-
-Node::Node(JSType expectedReturn)
-    : m_mayHaveDeclarations(false)
-    , m_expectedReturnType(expectedReturn)
+ParserRefCounted::ParserRefCounted()
 {
 #ifndef NDEBUG
-    ++NodeCounter::count;
+    ++ParserRefCountedCounter::count;
 #endif
-    m_line = lexer().lineNo();
-    if (!newNodes)
-        newNodes = new HashSet<Node*>;
-    newNodes->add(this);
+  if (!newTrackedObjects)
+      newTrackedObjects = new HashSet<ParserRefCounted*>;
+  newTrackedObjects->add(this);
+  ASSERT(newTrackedObjects->contains(this));
 }
 
-Node::~Node()
+ParserRefCounted::~ParserRefCounted()
 {
 #ifndef NDEBUG
-    --NodeCounter::count;
+    --ParserRefCountedCounter::count;
 #endif
 }
 
-void Node::ref()
+void ParserRefCounted::ref()
 {
     // bumping from 0 to 1 is just removing from the new nodes set
-    if (newNodes) {
-        HashSet<Node*>::iterator it = newNodes->find(this);
-        if (it != newNodes->end()) {
-            newNodes->remove(it);
-            ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(this));
+    if (newTrackedObjects) {
+        HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->find(this);
+        if (it != newTrackedObjects->end()) {
+            newTrackedObjects->remove(it);
+            ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
             return;
         }
     }   
 
-    ASSERT(!newNodes || !newNodes->contains(this));
+    ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
     
-    if (!nodeExtraRefCounts)
-        nodeExtraRefCounts = new HashCountedSet<Node*>;
-    nodeExtraRefCounts->add(this);
+    if (!trackedObjectExtraRefCounts)
+        trackedObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
+    trackedObjectExtraRefCounts->add(this);
 }
 
-void Node::deref()
+void ParserRefCounted::deref()
 {
-    ASSERT(!newNodes || !newNodes->contains(this));
+    ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
     
-    if (!nodeExtraRefCounts) {
+    if (!trackedObjectExtraRefCounts) {
         delete this;
         return;
     }
 
-    HashCountedSet<Node*>::iterator it = nodeExtraRefCounts->find(this);
-    if (it == nodeExtraRefCounts->end())
+    HashCountedSet<ParserRefCounted*>::iterator it = trackedObjectExtraRefCounts->find(this);
+    if (it == trackedObjectExtraRefCounts->end())
         delete this;
     else
-        nodeExtraRefCounts->remove(it);
+        trackedObjectExtraRefCounts->remove(it);
 }
 
-unsigned Node::refcount()
+unsigned ParserRefCounted::refcount()
 {
-    if (newNodes && newNodes->contains(this)) {
-        ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(this));
+    if (newTrackedObjects && newTrackedObjects->contains(this)) {
+        ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
         return 0;
     }
  
-    ASSERT(!newNodes || !newNodes->contains(this));
+    ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
 
-    if (!nodeExtraRefCounts)
+    if (!trackedObjectExtraRefCounts)
         return 1;
 
-    return 1 + nodeExtraRefCounts->count(this);
+    return 1 + trackedObjectExtraRefCounts->count(this);
 }
 
-void Node::clearNewNodes()
+void ParserRefCounted::deleteNewObjects()
 {
-    if (!newNodes)
+    if (!newTrackedObjects)
         return;
 
 #ifndef NDEBUG
-    HashSet<Node*>::iterator end = newNodes->end();
-    for (HashSet<Node*>::iterator it = newNodes->begin(); it != end; ++it)
-        ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(*it));
+    HashSet<ParserRefCounted*>::iterator end = newTrackedObjects->end();
+    for (HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->begin(); it != end; ++it)
+        ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(*it));
 #endif
-    deleteAllValues(*newNodes);
-    delete newNodes;
-    newNodes = 0;
+    deleteAllValues(*newTrackedObjects);
+    delete newTrackedObjects;
+    newTrackedObjects = 0;
+}
+
+Node::Node()
+    : m_mayHaveDeclarations(false)
+    , m_expectedReturnType(ObjectType)
+{
+  m_line = lexer().lineNo();
+}
+
+Node::Node(JSType expectedReturn)
+    : m_mayHaveDeclarations(false)
+    , m_expectedReturnType(expectedReturn)
+{
+    m_line = lexer().lineNo();
 }
 
 double ExpressionNode::evaluateToNumber(ExecState* exec)
@@ -4400,58 +4399,45 @@ Completion TryNode::execute(ExecState *exec)
 
 // ------------------------------ FunctionBodyNode -----------------------------
 
-ScopeNode::ScopeNode(SourceElements* children)
+ScopeNode::ScopeNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
     : BlockNode(children)
     , m_sourceURL(parser().sourceURL())
     , m_sourceId(parser().sourceId())
 {
-}
+    if (varStack)
+        m_varStack = *varStack;
 
-ProgramNode::ProgramNode(SourceElements* children)
-    : ScopeNode(children)
-{
+    if (funcStack)
+        m_functionStack = *funcStack;
 }
 
-EvalNode::EvalNode(SourceElements* children)
-    : ScopeNode(children)
+ProgramNode::ProgramNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+    : ScopeNode(children, varStack, funcStack)
 {
 }
 
-FunctionBodyNode::FunctionBodyNode(SourceElements* children)
-    : ScopeNode(children)
-    , m_initialized(false)
+EvalNode::EvalNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+    : ScopeNode(children, varStack, funcStack)
 {
 }
 
-void ScopeNode::initializeDeclarationStacks(ExecState* exec)
+FunctionBodyNode::FunctionBodyNode(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+    : ScopeNode(children, varStack, funcStack)
+    , m_initialized(false)
 {
-    DeclarationStacks::NodeStack nodeStack;
-    DeclarationStacks stacks(exec, nodeStack, m_varStack, m_functionStack);
-    Node* node = statementListInitializeDeclarationStack(*m_children, nodeStack);
-    if (!node)
-        return;
-    
-    while (true) {
-        ASSERT(node->mayHaveDeclarations()); // Otherwise, we wasted time putting an irrelevant node on the stack.
-        node->getDeclarations(stacks);
-        
-        size_t size = nodeStack.size();
-        if (!size)
-            break;
-        --size;
-        node = nodeStack[size];
-        nodeStack.shrink(size);
-    }
 }
 
-void FunctionBodyNode::initializeSymbolTable()
+void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
 {
     size_t i, size;
     size_t count = 0;
 
     // The order of additions here implicitly enforces the mutual exclusion described in ECMA 10.1.3.
-    for (i = 0, size = m_varStack.size(); i < size; ++i)
-        m_symbolTable.set(m_varStack[i]->ident.ustring().rep(), count++);
+    for (i = 0, size = m_varStack.size(); i < size; ++i) {
+        if (m_varStack[i]->ident != exec->propertyNames().arguments)
+            m_symbolTable.set(m_varStack[i]->ident.ustring().rep(), count);
+        count++;
+    }
 
     for (i = 0, size = m_parameters.size(); i < size; ++i)
         m_symbolTable.set(m_parameters[i].ustring().rep(), count++);
@@ -4482,8 +4468,7 @@ void FunctionBodyNode::optimizeVariableAccess()
 void FunctionBodyNode::processDeclarations(ExecState* exec)
 {
     if (!m_initialized) {
-        initializeDeclarationStacks(exec);
-        initializeSymbolTable();
+        initializeSymbolTable(exec);
         optimizeVariableAccess();
         
         m_initialized = true;
@@ -4520,8 +4505,6 @@ void FunctionBodyNode::processDeclarations(ExecState* exec)
 
 void ProgramNode::processDeclarations(ExecState* exec)
 {
-    initializeDeclarationStacks(exec);
-
     size_t i, size;
 
     JSVariableObject* variableObject = exec->variableObject();
@@ -4546,8 +4529,6 @@ void ProgramNode::processDeclarations(ExecState* exec)
 
 void EvalNode::processDeclarations(ExecState* exec)
 {
-    initializeDeclarationStacks(exec);
-
     size_t i, size;
 
     JSVariableObject* variableObject = exec->variableObject();
index 68f0274..4393f17 100644 (file)
@@ -111,18 +111,29 @@ namespace KJS {
       FunctionStack& functionStack;
   };
 
-  class Node : Noncopyable {
+  class ParserRefCounted : Noncopyable {
+  protected:
+    ParserRefCounted() KJS_FAST_CALL;
+    ParserRefCounted(PlacementNewAdoptType) KJS_FAST_CALL { }
+    
+  public:
+    void ref() KJS_FAST_CALL;
+    void deref() KJS_FAST_CALL;
+    unsigned refcount() KJS_FAST_CALL;
+    
+    static void deleteNewObjects() KJS_FAST_CALL;
+  
+    virtual ~ParserRefCounted();
+  };
+
+  class Node : public ParserRefCounted {
   public:
     Node() KJS_FAST_CALL;
-    Node(PlacementNewAdoptType) KJS_FAST_CALL { }
-    virtual ~Node();
+    Node(PlacementNewAdoptType placementAdopt) KJS_FAST_CALL
+    : ParserRefCounted(placementAdopt) { }
 
     UString toString() const KJS_FAST_CALL;
     int lineNo() const KJS_FAST_CALL { return m_line; }
-    void ref() KJS_FAST_CALL;
-    void deref() KJS_FAST_CALL;
-    unsigned refcount() KJS_FAST_CALL;
-    static void clearNewNodes() KJS_FAST_CALL;
 
     // Serialization.
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL = 0;
@@ -1844,6 +1855,7 @@ namespace KJS {
     virtual Completion execute(ExecState*) KJS_FAST_CALL;
     virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
     virtual void getDeclarations(DeclarationStacks&) KJS_FAST_CALL;
+    VarDeclNode* getVarDecl() { return varDecl.get(); }
   private:
     Identifier ident;
     RefPtr<AssignExprNode> init;
@@ -1951,13 +1963,12 @@ namespace KJS {
 
   class ScopeNode : public BlockNode {
   public:
-    ScopeNode(SourceElements*) KJS_FAST_CALL;
+    ScopeNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
 
     int sourceId() KJS_FAST_CALL { return m_sourceId; }
     const UString& sourceURL() KJS_FAST_CALL { return m_sourceURL; }
 
   protected:
-    void initializeDeclarationStacks(ExecState*) KJS_FAST_CALL;
 
     DeclarationStacks::VarStack m_varStack;
     DeclarationStacks::FunctionStack m_functionStack;
@@ -1969,7 +1980,7 @@ namespace KJS {
 
   class ProgramNode : public ScopeNode {
   public:
-    ProgramNode(SourceElements*) KJS_FAST_CALL;
+    ProgramNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
     virtual Completion execute(ExecState*) KJS_FAST_CALL;
     
   private:
@@ -1978,7 +1989,7 @@ namespace KJS {
 
   class EvalNode : public ScopeNode {
   public:
-    EvalNode(SourceElements*) KJS_FAST_CALL;
+    EvalNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
     virtual Completion execute(ExecState*) KJS_FAST_CALL;
     
   private:
@@ -1987,7 +1998,7 @@ namespace KJS {
 
   class FunctionBodyNode : public ScopeNode {
   public:
-    FunctionBodyNode(SourceElements*) KJS_FAST_CALL;
+    FunctionBodyNode(SourceElements*, DeclarationStacks::VarStack*, DeclarationStacks::FunctionStack*) KJS_FAST_CALL;
 
     virtual Completion execute(ExecState*) KJS_FAST_CALL;
 
@@ -1997,7 +2008,7 @@ namespace KJS {
     UString paramString() const KJS_FAST_CALL;
 
   private:
-    void initializeSymbolTable() KJS_FAST_CALL;
+    void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
     void optimizeVariableAccess() KJS_FAST_CALL;
     ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;