2008-11-20 Sam Weinig <sam@webkit.org>
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Nov 2008 23:23:59 +0000 (23:23 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Nov 2008 23:23:59 +0000 (23:23 +0000)
        Reviewed by Darin Adler.

        Patch for https://bugs.webkit.org/show_bug.cgi?id=22385
        <rdar://problem/6390179>
        Lazily reparse FunctionBodyNodes on first execution.

        - Saves 57MB on Membuster head.

        * bytecompiler/BytecodeGenerator.cpp:
        (JSC::BytecodeGenerator::generate): Remove vector shrinking since this is now
        handled by destroying the ScopeNodeData after generation.

        * parser/Grammar.y: Add alternate NoNode version of the grammar
        that does not create nodes.  This is used to lazily create FunctionBodyNodes
        on first execution.

        * parser/Lexer.cpp:
        (JSC::Lexer::setCode): Fix bug where on reparse, the Lexer was confused about
        what position and length meant. Position is the current position in the original
        data buffer (important for getting correct line/column information) and length
        the end offset in the original buffer.
        * parser/Lexer.h:
        (JSC::Lexer::sourceCode): Positions are relative to the beginning of the buffer.

        * parser/Nodes.cpp:
        (JSC::ScopeNodeData::ScopeNodeData): Move initialization of ScopeNode data here.
        (JSC::ScopeNode::ScopeNode): Add constructor that only sets the JSGlobalData
        for FunctionBodyNode stubs.
        (JSC::ScopeNode::~ScopeNode): Release m_children now that we don't inherit from
        BlockNode.
        (JSC::ScopeNode::releaseNodes): Ditto.
        (JSC::EvalNode::generateBytecode): Only shrink m_children, as we need to keep around
        the rest of the data.
        (JSC::FunctionBodyNode::FunctionBodyNode): Add constructor that only sets the
        JSGlobalData.
        (JSC::FunctionBodyNode::create): Ditto.
        (JSC::FunctionBodyNode::generateBytecode): If we don't have the data, do a reparse
        to construct it. Then after generation, destroy the data.
        (JSC::ProgramNode::generateBytecode): After generation, destroy the AST data.
        * parser/Nodes.h:
        (JSC::ExpressionNode::): Add isFuncExprNode for FunctionConstructor.
        (JSC::StatementNode::): Add isExprStatementNode for FunctionConstructor.
        (JSC::ExprStatementNode::): Ditto.
        (JSC::ExprStatementNode::expr): Add accessor for FunctionConstructor.
        (JSC::FuncExprNode::): Add isFuncExprNode for FunctionConstructor

        (JSC::ScopeNode::adoptData): Adopts a ScopeNodeData.
        (JSC::ScopeNode::data): Accessor for ScopeNodeData.
        (JSC::ScopeNode::destroyData): Deletes the ScopeNodeData.
        (JSC::ScopeNode::setFeatures): Added.
        (JSC::ScopeNode::varStack): Added assert.
        (JSC::ScopeNode::functionStack): Ditto.
        (JSC::ScopeNode::children): Ditto.
        (JSC::ScopeNode::neededConstants): Ditto.
        Factor m_varStack, m_functionStack, m_children and m_numConstants into ScopeNodeData.

        * parser/Parser.cpp:
        (JSC::Parser::reparse): Reparse the SourceCode in the FunctionBodyNode and set
        set up the ScopeNodeData for it.
        * parser/Parser.h:

        * parser/SourceCode.h:
        (JSC::SourceCode::endOffset): Added for use in the lexer.

        * runtime/FunctionConstructor.cpp:
        (JSC::getFunctionBody): Assuming a ProgramNode with one FunctionExpression in it,
        get the FunctionBodyNode.  Any issues signifies a parse failure in constructFunction.
        (JSC::constructFunction): Make parsing functions in the form new Function(""), easier
        by concatenating the strings together (with some glue) and parsing the function expression
        as a ProgramNode from which we can receive the FunctionBodyNode. This has the added benefit
        of not having special parsing code for the arguments and lazily constructing the
        FunctionBodyNode's AST on first execution.

        * runtime/Identifier.h:
        (JSC::operator!=): Added.

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

12 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
JavaScriptCore/parser/Grammar.y
JavaScriptCore/parser/Lexer.cpp
JavaScriptCore/parser/Lexer.h
JavaScriptCore/parser/Nodes.cpp
JavaScriptCore/parser/Nodes.h
JavaScriptCore/parser/Parser.cpp
JavaScriptCore/parser/Parser.h
JavaScriptCore/parser/SourceCode.h
JavaScriptCore/runtime/FunctionConstructor.cpp
JavaScriptCore/runtime/Identifier.h

index 03b267f..77f5c61 100644 (file)
@@ -1,5 +1,83 @@
 2008-11-20  Sam Weinig  <sam@webkit.org>
 
+        Reviewed by Darin Adler.
+
+        Patch for https://bugs.webkit.org/show_bug.cgi?id=22385
+        <rdar://problem/6390179>
+        Lazily reparse FunctionBodyNodes on first execution.
+
+        - Saves 57MB on Membuster head.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate): Remove vector shrinking since this is now
+        handled by destroying the ScopeNodeData after generation.
+
+        * parser/Grammar.y: Add alternate NoNode version of the grammar
+        that does not create nodes.  This is used to lazily create FunctionBodyNodes
+        on first execution.
+
+        * parser/Lexer.cpp:
+        (JSC::Lexer::setCode): Fix bug where on reparse, the Lexer was confused about
+        what position and length meant. Position is the current position in the original
+        data buffer (important for getting correct line/column information) and length
+        the end offset in the original buffer.
+        * parser/Lexer.h:
+        (JSC::Lexer::sourceCode): Positions are relative to the beginning of the buffer.
+
+        * parser/Nodes.cpp:
+        (JSC::ScopeNodeData::ScopeNodeData): Move initialization of ScopeNode data here.
+        (JSC::ScopeNode::ScopeNode): Add constructor that only sets the JSGlobalData
+        for FunctionBodyNode stubs.
+        (JSC::ScopeNode::~ScopeNode): Release m_children now that we don't inherit from
+        BlockNode.
+        (JSC::ScopeNode::releaseNodes): Ditto.
+        (JSC::EvalNode::generateBytecode): Only shrink m_children, as we need to keep around
+        the rest of the data.
+        (JSC::FunctionBodyNode::FunctionBodyNode): Add constructor that only sets the
+        JSGlobalData. 
+        (JSC::FunctionBodyNode::create): Ditto.
+        (JSC::FunctionBodyNode::generateBytecode): If we don't have the data, do a reparse
+        to construct it. Then after generation, destroy the data.
+        (JSC::ProgramNode::generateBytecode): After generation, destroy the AST data.
+        * parser/Nodes.h:
+        (JSC::ExpressionNode::): Add isFuncExprNode for FunctionConstructor.
+        (JSC::StatementNode::): Add isExprStatementNode for FunctionConstructor.
+        (JSC::ExprStatementNode::): Ditto.
+        (JSC::ExprStatementNode::expr): Add accessor for FunctionConstructor.
+        (JSC::FuncExprNode::): Add isFuncExprNode for FunctionConstructor
+
+        (JSC::ScopeNode::adoptData): Adopts a ScopeNodeData.
+        (JSC::ScopeNode::data): Accessor for ScopeNodeData.
+        (JSC::ScopeNode::destroyData): Deletes the ScopeNodeData.
+        (JSC::ScopeNode::setFeatures): Added.
+        (JSC::ScopeNode::varStack): Added assert.
+        (JSC::ScopeNode::functionStack): Ditto.
+        (JSC::ScopeNode::children): Ditto.
+        (JSC::ScopeNode::neededConstants): Ditto.
+        Factor m_varStack, m_functionStack, m_children and m_numConstants into ScopeNodeData.
+
+        * parser/Parser.cpp:
+        (JSC::Parser::reparse): Reparse the SourceCode in the FunctionBodyNode and set
+        set up the ScopeNodeData for it. 
+        * parser/Parser.h:
+
+        * parser/SourceCode.h:
+        (JSC::SourceCode::endOffset): Added for use in the lexer.
+
+        * runtime/FunctionConstructor.cpp:
+        (JSC::getFunctionBody): Assuming a ProgramNode with one FunctionExpression in it,
+        get the FunctionBodyNode.  Any issues signifies a parse failure in constructFunction. 
+        (JSC::constructFunction): Make parsing functions in the form new Function(""), easier
+        by concatenating the strings together (with some glue) and parsing the function expression
+        as a ProgramNode from which we can receive the FunctionBodyNode. This has the added benefit
+        of not having special parsing code for the arguments and lazily constructing the 
+        FunctionBodyNode's AST on first execution.
+
+        * runtime/Identifier.h:
+        (JSC::operator!=): Added.
+
+2008-11-20  Sam Weinig  <sam@webkit.org>
+
         Reviewed by Geoffrey Garen.
 
         Speedup the lexer to offset coming re-parsing patch.
index ff8689a..b92cb64 100644 (file)
@@ -139,12 +139,6 @@ void BytecodeGenerator::generate()
         m_codeBlock->dump(globalObject->globalExec());
     }
 #endif
-
-    m_scopeNode->children().shrinkCapacity(0);
-    if (m_codeType != EvalCode) { // eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time.
-        m_scopeNode->varStack().shrinkCapacity(0);
-        m_scopeNode->functionStack().shrinkCapacity(0);
-    }
     
     m_codeBlock->instructions.shrinkToFit();
     m_codeBlock->globalResolveInstructions.shrinkToFit();
index 3d6e57c..e13855e 100644 (file)
@@ -283,6 +283,10 @@ static inline void appendToVarDeclarationList(void* globalPtr, ParserRefCountedD
 %type <propertyList>    PropertyList
 %%
 
+// FIXME: There are currently two versions of the grammar in this file, the normal one, and the NoNodes version used for
+// lazy recompilation of FunctionBodyNodes.  We should move to generating the two versions from a script to avoid bugs.
+// In the mean time, make sure to make any changes to the grammar in both versions.
+
 Literal:
     NULLTOKEN                           { $$ = createNodeInfo<ExpressionNode*>(new NullNode(GLOBAL_DATA), 0, 1); }
   | TRUETOKEN                           { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, true), 0, 1); }
@@ -1203,21 +1207,8 @@ FormalParameterList:
 ;
 
 FunctionBody:
-    /* not in spec */           { $$ = FunctionBodyNode::create(GLOBAL_DATA, 0, 0, 0, NoFeatures, 0); }
-  | SourceElements              { $$ = FunctionBodyNode::create(GLOBAL_DATA, $1.m_node, $1.m_varDeclarations ? &$1.m_varDeclarations->data : 0, 
-                                                                $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0,
-                                                                $1.m_features, $1.m_numConstants);
-                                  // 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();
-                                  }
-                                }
+    /* not in spec */                   { $$ = FunctionBodyNode::create(GLOBAL_DATA); }
+  | SourceElements_NoNode               { $$ = FunctionBodyNode::create(GLOBAL_DATA); }
 ;
 
 Program:
@@ -1247,6 +1238,598 @@ SourceElement:
   | Statement                           { $$ = $1; }
 ;
  
+// Start NoNodes
+
+Literal_NoNode:
+    NULLTOKEN
+  | TRUETOKEN
+  | FALSETOKEN
+  | NUMBER
+  | STRING
+  | '/' /* regexp */ { Lexer& l = *LEXER; if (!l.scanRegExp()) YYABORT; }
+  | DIVEQUAL /* regexp with /= */ { Lexer& l = *LEXER; if (!l.scanRegExp()) YYABORT; }
+;
+
+Property_NoNode:
+    IDENT ':' AssignmentExpr_NoNode
+  | STRING ':' AssignmentExpr_NoNode
+  | NUMBER ':' AssignmentExpr_NoNode
+  | IDENT IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE { if (*$1 != "get" && *$1 != "set") YYABORT; }
+  | IDENT IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE { if (*$1 != "get" && *$1 != "set") YYABORT; }
+;
+
+PropertyList_NoNode:
+    Property_NoNode
+  | PropertyList_NoNode ',' Property_NoNode
+;
+
+PrimaryExpr_NoNode:
+    PrimaryExprNoBrace_NoNode
+  | OPENBRACE CLOSEBRACE
+  | OPENBRACE PropertyList_NoNode CLOSEBRACE
+  /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
+  | OPENBRACE PropertyList_NoNode ',' CLOSEBRACE
+;
+
+PrimaryExprNoBrace_NoNode:
+    THISTOKEN
+  | Literal_NoNode
+  | ArrayLiteral_NoNode
+  | IDENT
+  | '(' Expr_NoNode ')'
+;
+
+ArrayLiteral_NoNode:
+    '[' ElisionOpt_NoNode ']'
+  | '[' ElementList_NoNode ']'
+  | '[' ElementList_NoNode ',' ElisionOpt_NoNode ']'
+;
+
+ElementList_NoNode:
+    ElisionOpt_NoNode AssignmentExpr_NoNode
+  | ElementList_NoNode ',' ElisionOpt_NoNode AssignmentExpr_NoNode
+;
+
+ElisionOpt_NoNode:
+    /* nothing */
+  | Elision_NoNode
+;
+
+Elision_NoNode:
+    ','
+  | Elision_NoNode ','
+;
+
+MemberExpr_NoNode:
+    PrimaryExpr_NoNode
+  | FunctionExpr_NoNode
+  | MemberExpr_NoNode '[' Expr_NoNode ']'
+  | MemberExpr_NoNode '.' IDENT
+  | NEW MemberExpr_NoNode Arguments_NoNode
+;
+
+MemberExprNoBF_NoNode:
+    PrimaryExprNoBrace_NoNode
+  | MemberExprNoBF_NoNode '[' Expr_NoNode ']'
+  | MemberExprNoBF_NoNode '.' IDENT
+  | NEW MemberExpr_NoNode Arguments_NoNode
+;
+
+NewExpr_NoNode:
+    MemberExpr_NoNode
+  | NEW NewExpr_NoNode
+;
+
+NewExprNoBF_NoNode:
+    MemberExprNoBF_NoNode
+  | NEW NewExpr_NoNode
+;
+
+CallExpr_NoNode:
+    MemberExpr_NoNode Arguments_NoNode
+  | CallExpr_NoNode Arguments_NoNode
+  | CallExpr_NoNode '[' Expr_NoNode ']'
+  | CallExpr_NoNode '.' IDENT
+;
+
+CallExprNoBF_NoNode:
+    MemberExprNoBF_NoNode Arguments_NoNode
+  | CallExprNoBF_NoNode Arguments_NoNode
+  | CallExprNoBF_NoNode '[' Expr_NoNode ']'
+  | CallExprNoBF_NoNode '.' IDENT
+;
+
+Arguments_NoNode:
+    '(' ')'
+  | '(' ArgumentList_NoNode ')'
+;
+
+ArgumentList_NoNode:
+    AssignmentExpr_NoNode
+  | ArgumentList_NoNode ',' AssignmentExpr_NoNode
+;
+
+LeftHandSideExpr_NoNode:
+    NewExpr_NoNode
+  | CallExpr_NoNode
+;
+
+LeftHandSideExprNoBF_NoNode:
+    NewExprNoBF_NoNode
+  | CallExprNoBF_NoNode
+;
+
+PostfixExpr_NoNode:
+    LeftHandSideExpr_NoNode
+  | LeftHandSideExpr_NoNode PLUSPLUS
+  | LeftHandSideExpr_NoNode MINUSMINUS
+;
+
+PostfixExprNoBF_NoNode:
+    LeftHandSideExprNoBF_NoNode
+  | LeftHandSideExprNoBF_NoNode PLUSPLUS
+  | LeftHandSideExprNoBF_NoNode MINUSMINUS
+;
+
+UnaryExprCommon_NoNode:
+    DELETETOKEN UnaryExpr_NoNode
+  | VOIDTOKEN UnaryExpr_NoNode
+  | TYPEOF UnaryExpr_NoNode
+  | PLUSPLUS UnaryExpr_NoNode
+  | AUTOPLUSPLUS UnaryExpr_NoNode
+  | MINUSMINUS UnaryExpr_NoNode
+  | AUTOMINUSMINUS UnaryExpr_NoNode
+  | '+' UnaryExpr_NoNode
+  | '-' UnaryExpr_NoNode
+  | '~' UnaryExpr_NoNode
+  | '!' UnaryExpr_NoNode
+
+UnaryExpr_NoNode:
+    PostfixExpr_NoNode
+  | UnaryExprCommon_NoNode
+;
+
+UnaryExprNoBF_NoNode:
+    PostfixExprNoBF_NoNode
+  | UnaryExprCommon_NoNode
+;
+
+MultiplicativeExpr_NoNode:
+    UnaryExpr_NoNode
+  | MultiplicativeExpr_NoNode '*' UnaryExpr_NoNode
+  | MultiplicativeExpr_NoNode '/' UnaryExpr_NoNode
+  | MultiplicativeExpr_NoNode '%' UnaryExpr_NoNode
+;
+
+MultiplicativeExprNoBF_NoNode:
+    UnaryExprNoBF_NoNode
+  | MultiplicativeExprNoBF_NoNode '*' UnaryExpr_NoNode
+  | MultiplicativeExprNoBF_NoNode '/' UnaryExpr_NoNode
+  | MultiplicativeExprNoBF_NoNode '%' UnaryExpr_NoNode
+;
+
+AdditiveExpr_NoNode:
+    MultiplicativeExpr_NoNode
+  | AdditiveExpr_NoNode '+' MultiplicativeExpr_NoNode
+  | AdditiveExpr_NoNode '-' MultiplicativeExpr_NoNode
+;
+
+AdditiveExprNoBF_NoNode:
+    MultiplicativeExprNoBF_NoNode
+  | AdditiveExprNoBF_NoNode '+' MultiplicativeExpr_NoNode
+  | AdditiveExprNoBF_NoNode '-' MultiplicativeExpr_NoNode
+;
+
+ShiftExpr_NoNode:
+    AdditiveExpr_NoNode
+  | ShiftExpr_NoNode LSHIFT AdditiveExpr_NoNode
+  | ShiftExpr_NoNode RSHIFT AdditiveExpr_NoNode
+  | ShiftExpr_NoNode URSHIFT AdditiveExpr_NoNode
+;
+
+ShiftExprNoBF_NoNode:
+    AdditiveExprNoBF_NoNode
+  | ShiftExprNoBF_NoNode LSHIFT AdditiveExpr_NoNode
+  | ShiftExprNoBF_NoNode RSHIFT AdditiveExpr_NoNode
+  | ShiftExprNoBF_NoNode URSHIFT AdditiveExpr_NoNode
+;
+
+RelationalExpr_NoNode:
+    ShiftExpr_NoNode
+  | RelationalExpr_NoNode '<' ShiftExpr_NoNode
+  | RelationalExpr_NoNode '>' ShiftExpr_NoNode
+  | RelationalExpr_NoNode LE ShiftExpr_NoNode
+  | RelationalExpr_NoNode GE ShiftExpr_NoNode
+  | RelationalExpr_NoNode INSTANCEOF ShiftExpr_NoNode
+  | RelationalExpr_NoNode INTOKEN ShiftExpr_NoNode
+;
+
+RelationalExprNoIn_NoNode:
+    ShiftExpr_NoNode
+  | RelationalExprNoIn_NoNode '<' ShiftExpr_NoNode
+  | RelationalExprNoIn_NoNode '>' ShiftExpr_NoNode
+  | RelationalExprNoIn_NoNode LE ShiftExpr_NoNode
+  | RelationalExprNoIn_NoNode GE ShiftExpr_NoNode
+  | RelationalExprNoIn_NoNode INSTANCEOF ShiftExpr_NoNode
+;
+
+RelationalExprNoBF_NoNode:
+    ShiftExprNoBF_NoNode
+  | RelationalExprNoBF_NoNode '<' ShiftExpr_NoNode
+  | RelationalExprNoBF_NoNode '>' ShiftExpr_NoNode
+  | RelationalExprNoBF_NoNode LE ShiftExpr_NoNode
+  | RelationalExprNoBF_NoNode GE ShiftExpr_NoNode
+  | RelationalExprNoBF_NoNode INSTANCEOF ShiftExpr_NoNode
+  | RelationalExprNoBF_NoNode INTOKEN ShiftExpr_NoNode
+;
+
+EqualityExpr_NoNode:
+    RelationalExpr_NoNode
+  | EqualityExpr_NoNode EQEQ RelationalExpr_NoNode
+  | EqualityExpr_NoNode NE RelationalExpr_NoNode
+  | EqualityExpr_NoNode STREQ RelationalExpr_NoNode
+  | EqualityExpr_NoNode STRNEQ RelationalExpr_NoNode
+;
+
+EqualityExprNoIn_NoNode:
+    RelationalExprNoIn_NoNode
+  | EqualityExprNoIn_NoNode EQEQ RelationalExprNoIn_NoNode
+  | EqualityExprNoIn_NoNode NE RelationalExprNoIn_NoNode
+  | EqualityExprNoIn_NoNode STREQ RelationalExprNoIn_NoNode
+  | EqualityExprNoIn_NoNode STRNEQ RelationalExprNoIn_NoNode
+;
+
+EqualityExprNoBF_NoNode:
+    RelationalExprNoBF_NoNode
+  | EqualityExprNoBF_NoNode EQEQ RelationalExpr_NoNode
+  | EqualityExprNoBF_NoNode NE RelationalExpr_NoNode
+  | EqualityExprNoBF_NoNode STREQ RelationalExpr_NoNode
+  | EqualityExprNoBF_NoNode STRNEQ RelationalExpr_NoNode
+;
+
+BitwiseANDExpr_NoNode:
+    EqualityExpr_NoNode
+  | BitwiseANDExpr_NoNode '&' EqualityExpr_NoNode
+;
+
+BitwiseANDExprNoIn_NoNode:
+    EqualityExprNoIn_NoNode
+  | BitwiseANDExprNoIn_NoNode '&' EqualityExprNoIn_NoNode
+;
+
+BitwiseANDExprNoBF_NoNode:
+    EqualityExprNoBF_NoNode
+  | BitwiseANDExprNoBF_NoNode '&' EqualityExpr_NoNode
+;
+
+BitwiseXORExpr_NoNode:
+    BitwiseANDExpr_NoNode
+  | BitwiseXORExpr_NoNode '^' BitwiseANDExpr_NoNode
+;
+
+BitwiseXORExprNoIn_NoNode:
+    BitwiseANDExprNoIn_NoNode
+  | BitwiseXORExprNoIn_NoNode '^' BitwiseANDExprNoIn_NoNode
+;
+
+BitwiseXORExprNoBF_NoNode:
+    BitwiseANDExprNoBF_NoNode
+  | BitwiseXORExprNoBF_NoNode '^' BitwiseANDExpr_NoNode
+;
+
+BitwiseORExpr_NoNode:
+    BitwiseXORExpr_NoNode
+  | BitwiseORExpr_NoNode '|' BitwiseXORExpr_NoNode
+;
+
+BitwiseORExprNoIn_NoNode:
+    BitwiseXORExprNoIn_NoNode
+  | BitwiseORExprNoIn_NoNode '|' BitwiseXORExprNoIn_NoNode
+;
+
+BitwiseORExprNoBF_NoNode:
+    BitwiseXORExprNoBF_NoNode
+  | BitwiseORExprNoBF_NoNode '|' BitwiseXORExpr_NoNode
+;
+
+LogicalANDExpr_NoNode:
+    BitwiseORExpr_NoNode
+  | LogicalANDExpr_NoNode AND BitwiseORExpr_NoNode
+;
+
+LogicalANDExprNoIn_NoNode:
+    BitwiseORExprNoIn_NoNode
+  | LogicalANDExprNoIn_NoNode AND BitwiseORExprNoIn_NoNode
+;
+
+LogicalANDExprNoBF_NoNode:
+    BitwiseORExprNoBF_NoNode
+  | LogicalANDExprNoBF_NoNode AND BitwiseORExpr_NoNode
+;
+
+LogicalORExpr_NoNode:
+    LogicalANDExpr_NoNode
+  | LogicalORExpr_NoNode OR LogicalANDExpr_NoNode
+;
+
+LogicalORExprNoIn_NoNode:
+    LogicalANDExprNoIn_NoNode
+  | LogicalORExprNoIn_NoNode OR LogicalANDExprNoIn_NoNode
+;
+
+LogicalORExprNoBF_NoNode:
+    LogicalANDExprNoBF_NoNode
+  | LogicalORExprNoBF_NoNode OR LogicalANDExpr_NoNode
+;
+
+ConditionalExpr_NoNode:
+    LogicalORExpr_NoNode
+  | LogicalORExpr_NoNode '?' AssignmentExpr_NoNode ':' AssignmentExpr_NoNode
+;
+
+ConditionalExprNoIn_NoNode:
+    LogicalORExprNoIn_NoNode
+  | LogicalORExprNoIn_NoNode '?' AssignmentExprNoIn_NoNode ':' AssignmentExprNoIn_NoNode
+;
+
+ConditionalExprNoBF_NoNode:
+    LogicalORExprNoBF_NoNode
+  | LogicalORExprNoBF_NoNode '?' AssignmentExpr_NoNode ':' AssignmentExpr_NoNode
+;
+
+AssignmentExpr_NoNode:
+    ConditionalExpr_NoNode
+  | LeftHandSideExpr_NoNode AssignmentOperator_NoNode AssignmentExpr_NoNode
+;
+
+AssignmentExprNoIn_NoNode:
+    ConditionalExprNoIn_NoNode
+  | LeftHandSideExpr_NoNode AssignmentOperator_NoNode AssignmentExprNoIn_NoNode
+;
+
+AssignmentExprNoBF_NoNode:
+    ConditionalExprNoBF_NoNode
+  | LeftHandSideExprNoBF_NoNode AssignmentOperator_NoNode AssignmentExpr_NoNode
+;
+
+AssignmentOperator_NoNode:
+    '='
+  | PLUSEQUAL
+  | MINUSEQUAL
+  | MULTEQUAL
+  | DIVEQUAL
+  | LSHIFTEQUAL
+  | RSHIFTEQUAL
+  | URSHIFTEQUAL
+  | ANDEQUAL
+  | XOREQUAL
+  | OREQUAL
+  | MODEQUAL
+;
+
+Expr_NoNode:
+    AssignmentExpr_NoNode
+  | Expr_NoNode ',' AssignmentExpr_NoNode
+;
+
+ExprNoIn_NoNode:
+    AssignmentExprNoIn_NoNode
+  | ExprNoIn_NoNode ',' AssignmentExprNoIn_NoNode
+;
+
+ExprNoBF_NoNode:
+    AssignmentExprNoBF_NoNode
+  | ExprNoBF_NoNode ',' AssignmentExpr_NoNode
+;
+
+Statement_NoNode:
+    Block_NoNode
+  | VariableStatement_NoNode
+  | ConstStatement_NoNode
+  | EmptyStatement_NoNode
+  | ExprStatement_NoNode
+  | IfStatement_NoNode
+  | IterationStatement_NoNode
+  | ContinueStatement_NoNode
+  | BreakStatement_NoNode
+  | ReturnStatement_NoNode
+  | WithStatement_NoNode
+  | SwitchStatement_NoNode
+  | LabelledStatement_NoNode
+  | ThrowStatement_NoNode
+  | TryStatement_NoNode
+  | DebuggerStatement_NoNode
+;
+
+Block_NoNode:
+    OPENBRACE CLOSEBRACE
+  | OPENBRACE SourceElements_NoNode CLOSEBRACE
+;
+
+VariableStatement_NoNode:
+    VAR VariableDeclarationList_NoNode ';'
+  | VAR VariableDeclarationList_NoNode error { AUTO_SEMICOLON; }
+;
+
+VariableDeclarationList_NoNode:
+    IDENT
+  | IDENT Initializer_NoNode
+  | VariableDeclarationList_NoNode ',' IDENT
+  | VariableDeclarationList_NoNode ',' IDENT Initializer_NoNode
+;
+
+VariableDeclarationListNoIn_NoNode:
+    IDENT
+  | IDENT InitializerNoIn_NoNode
+  | VariableDeclarationListNoIn_NoNode ',' IDENT
+  | VariableDeclarationListNoIn_NoNode ',' IDENT InitializerNoIn_NoNode
+;
+
+ConstStatement_NoNode:
+    CONSTTOKEN ConstDeclarationList_NoNode ';'
+  | CONSTTOKEN ConstDeclarationList_NoNode error { AUTO_SEMICOLON; }
+;
+
+ConstDeclarationList_NoNode:
+    ConstDeclaration_NoNode
+  | ConstDeclarationList_NoNode ',' ConstDeclaration_NoNode
+;
+
+ConstDeclaration_NoNode:
+    IDENT
+  | IDENT Initializer_NoNode
+;
+
+Initializer_NoNode:
+    '=' AssignmentExpr_NoNode
+;
+
+InitializerNoIn_NoNode:
+    '=' AssignmentExprNoIn_NoNode
+;
+
+EmptyStatement_NoNode:
+    ';'
+;
+
+ExprStatement_NoNode:
+    ExprNoBF_NoNode ';'
+  | ExprNoBF_NoNode error { AUTO_SEMICOLON; }
+;
+
+IfStatement_NoNode:
+    IF '(' Expr_NoNode ')' Statement_NoNode %prec IF_WITHOUT_ELSE
+  | IF '(' Expr_NoNode ')' Statement_NoNode ELSE Statement_NoNode
+;
+
+IterationStatement_NoNode:
+    DO Statement_NoNode WHILE '(' Expr_NoNode ')' ';'
+  | DO Statement_NoNode WHILE '(' Expr_NoNode ')' error // Always performs automatic semicolon insertion
+  | WHILE '(' Expr_NoNode ')' Statement_NoNode
+  | FOR '(' ExprNoInOpt_NoNode ';' ExprOpt_NoNode ';' ExprOpt_NoNode ')' Statement_NoNode
+  | FOR '(' VAR VariableDeclarationListNoIn_NoNode ';' ExprOpt_NoNode ';' ExprOpt_NoNode ')' Statement_NoNode
+  | FOR '(' LeftHandSideExpr_NoNode INTOKEN Expr_NoNode ')' Statement_NoNode
+  | FOR '(' VAR IDENT INTOKEN Expr_NoNode ')' Statement_NoNode
+  | FOR '(' VAR IDENT InitializerNoIn_NoNode INTOKEN Expr_NoNode ')' Statement_NoNode
+;
+
+ExprOpt_NoNode:
+    /* nothing */
+  | Expr_NoNode
+;
+
+ExprNoInOpt_NoNode:
+    /* nothing */
+  | ExprNoIn_NoNode
+;
+
+ContinueStatement_NoNode:
+    CONTINUE ';'
+  | CONTINUE error { AUTO_SEMICOLON; }
+  | CONTINUE IDENT ';'
+  | CONTINUE IDENT error { AUTO_SEMICOLON; }
+;
+
+BreakStatement_NoNode:
+    BREAK ';'
+  | BREAK error { AUTO_SEMICOLON; }
+  | BREAK IDENT ';'
+  | BREAK IDENT error { AUTO_SEMICOLON; }
+;
+
+ReturnStatement_NoNode:
+    RETURN ';'
+  | RETURN error { AUTO_SEMICOLON; }
+  | RETURN Expr_NoNode ';'
+  | RETURN Expr_NoNode error { AUTO_SEMICOLON; }
+;
+
+WithStatement_NoNode:
+    WITH '(' Expr_NoNode ')' Statement_NoNode
+;
+
+SwitchStatement_NoNode:
+    SWITCH '(' Expr_NoNode ')' CaseBlock_NoNode
+;
+
+CaseBlock_NoNode:
+    OPENBRACE CaseClausesOpt_NoNode CLOSEBRACE
+  | OPENBRACE CaseClausesOpt_NoNode DefaultClause_NoNode CaseClausesOpt_NoNode CLOSEBRACE
+;
+
+CaseClausesOpt_NoNode:
+    /* nothing */
+  | CaseClauses_NoNode
+;
+
+CaseClauses_NoNode:
+    CaseClause_NoNode
+  | CaseClauses_NoNode CaseClause_NoNode
+;
+
+CaseClause_NoNode:
+    CASE Expr_NoNode ':'
+  | CASE Expr_NoNode ':' SourceElements_NoNode
+;
+
+DefaultClause_NoNode:
+    DEFAULT ':'
+  | DEFAULT ':' SourceElements_NoNode
+;
+
+LabelledStatement_NoNode:
+    IDENT ':' Statement_NoNode;
+
+ThrowStatement_NoNode:
+    THROW Expr_NoNode ';'
+  | THROW Expr_NoNode error { AUTO_SEMICOLON; }
+;
+
+TryStatement_NoNode:
+    TRY Block_NoNode FINALLY Block_NoNode
+  | TRY Block_NoNode CATCH '(' IDENT ')' Block_NoNode
+  | TRY Block_NoNode CATCH '(' IDENT ')' Block_NoNode FINALLY Block_NoNode
+;
+
+DebuggerStatement_NoNode:
+    DEBUGGER ';'
+  | DEBUGGER error { AUTO_SEMICOLON; }
+;
+
+FunctionDeclaration_NoNode:
+    FUNCTION IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
+  | FUNCTION IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
+;
+
+FunctionExpr_NoNode:
+    FUNCTION '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
+  | FUNCTION '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
+  | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
+  | FUNCTION IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE
+;
+
+FormalParameterList_NoNode:
+    IDENT
+  | FormalParameterList_NoNode ',' IDENT
+;
+
+FunctionBody_NoNode:
+    /* not in spec */
+  | SourceElements_NoNode
+;
+
+SourceElements_NoNode:
+    SourceElement_NoNode
+  | SourceElements_NoNode SourceElement_NoNode
+;
+
+SourceElement_NoNode:
+    FunctionDeclaration_NoNode
+  | Statement_NoNode
+;
+
+// End NoNodes
+
 %%
 
 static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end)
index 7b11128..fd56de3 100644 (file)
@@ -96,10 +96,10 @@ void Lexer::setCode(const SourceCode& source)
     m_stackToken = -1;
     m_lastToken = -1;
 
-    m_position = 0;
+    m_position = source.startOffset();
     m_source = &source;
-    m_code = source.data();
-    m_length = source.length();
+    m_code = source.provider()->data();
+    m_length = source.endOffset();
     m_skipLF = false;
     m_skipCR = false;
     m_error = false;
index 3fc20c7..3cb7302 100644 (file)
@@ -88,7 +88,7 @@ namespace JSC {
         bool sawError() const { return m_error; }
 
         void clear();
-        SourceCode sourceCode(int openBrace, int closeBrace, int firstLine) { return SourceCode(m_source->provider(), m_source->startOffset() + openBrace + 1, m_source->startOffset() + closeBrace, firstLine); }
+        SourceCode sourceCode(int openBrace, int closeBrace, int firstLine) { return SourceCode(m_source->provider(), openBrace + 1, closeBrace, firstLine); }
 
     private:
         friend class JSGlobalData;
index d212996..17f16eb 100644 (file)
@@ -2377,23 +2377,55 @@ void ParameterNode::releaseNodes(NodeReleaser& releaser)
     releaser.release(m_next);
 }
 
-// ------------------------------ ScopeNode -----------------------------
+// -----------------------------ScopeNodeData ---------------------------
 
-ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
-    : BlockNode(globalData, children)
-    , m_source(source)
-    , m_features(features)
-    , m_numConstants(numConstants)
+ScopeNodeData::ScopeNodeData(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, int numConstants)
+    : m_numConstants(numConstants)
 {
     if (varStack)
         m_varStack = *varStack;
     if (funcStack)
         m_functionStack = *funcStack;
+    if (children)
+        children->releaseContentsIntoVector(m_children);
+}
+
+// ------------------------------ ScopeNode -----------------------------
+
+ScopeNode::ScopeNode(JSGlobalData* globalData)
+    : StatementNode(globalData)
+    , m_features(NoFeatures)
+{
 #if ENABLE(OPCODE_SAMPLING)
     globalData->interpreter->sampler()->notifyOfScope(this);
 #endif
 }
 
+ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
+    : StatementNode(globalData)
+    , m_data(new ScopeNodeData(children, varStack, funcStack, numConstants))
+    , m_features(features)
+    , m_source(source)
+{
+#if ENABLE(OPCODE_SAMPLING)
+    globalData->interpreter->sampler()->notifyOfScope(this);
+#endif
+}
+
+ScopeNode::~ScopeNode()
+{
+    NodeReleaser::releaseAllNodes(this);
+}
+
+void ScopeNode::releaseNodes(NodeReleaser& releaser)
+{
+    if (!m_data)
+        return;
+    size_t size = m_data->m_children.size();
+    for (size_t i = 0; i < size; ++i)
+        releaser.release(m_data->m_children[i]);
+}
+
 // ------------------------------ ProgramNode -----------------------------
 
 ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
@@ -2435,6 +2467,10 @@ void EvalNode::generateBytecode(ScopeChainNode* scopeChainNode)
 
     BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable, m_code.get());
     generator.generate();
+
+    // Eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time,
+    // so the entire ScopeNodeData cannot be destoyed.
+    children().clear();
 }
 
 EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
@@ -2444,6 +2480,14 @@ EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, V
 
 // ------------------------------ FunctionBodyNode -----------------------------
 
+FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData)
+    : ScopeNode(globalData)
+    , m_parameters(0)
+    , m_parameterCount(0)
+    , m_refCount(0)
+{
+}
+
 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)
     , m_parameters(0)
@@ -2482,9 +2526,9 @@ void FunctionBodyNode::mark()
         m_code->mark();
 }
 
-FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData)
 {
-    return new FunctionBodyNode(globalData, children, varStack, funcStack, SourceCode(), features, numConstants);
+    return new FunctionBodyNode(globalData);
 }
 
 FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
@@ -2494,6 +2538,12 @@ FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceEleme
 
 void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode)
 {
+    // This branch is only necessary since you can still create a non-stub FunctionBodyNode by
+    // calling Parser::parse<FunctionBodyNode>().   
+    if (!data())
+        scopeChainNode->globalData->parser->reparse(scopeChainNode->globalData, this);
+    ASSERT(data());
+
     ScopeChain scopeChain(scopeChainNode);
     JSGlobalObject* globalObject = scopeChain.globalObject();
 
@@ -2501,6 +2551,8 @@ void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode)
 
     BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable, m_code.get());
     generator.generate();
+
+    destroyData();
 }
 
 RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
@@ -2537,6 +2589,8 @@ void ProgramNode::generateBytecode(ScopeChainNode* scopeChainNode)
     
     BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get());
     generator.generate();
+
+    destroyData();
 }
 
 UString FunctionBodyNode::paramString() const
index 9f2f128..f5d775e 100644 (file)
@@ -170,6 +170,7 @@ namespace JSC {
         virtual bool isResolveNode() const JSC_FAST_CALL { return false; }
         virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; }
         virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; }
+        virtual bool isFuncExprNode() const JSC_FAST_CALL { return false; } 
 
         virtual ExpressionNode* stripUnaryPlus() { return this; }
 
@@ -191,6 +192,7 @@ namespace JSC {
 
         virtual bool isEmptyStatement() const JSC_FAST_CALL { return false; }
         virtual bool isReturnNode() const JSC_FAST_CALL { return false; }
+        virtual bool isExprStatement() const JSC_FAST_CALL { return false; }
 
         virtual bool isBlock() const JSC_FAST_CALL { return false; }
         virtual bool isLoop() const JSC_FAST_CALL { return false; }
@@ -1742,8 +1744,12 @@ namespace JSC {
         {
         }
 
+        virtual bool isExprStatement() const JSC_FAST_CALL { return true; }
+
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
 
+        ExpressionNode* expr() const { return m_expr.get(); }
+
     private:
         RefPtr<ExpressionNode> m_expr;
     };
@@ -2056,43 +2062,63 @@ namespace JSC {
         RefPtr<ParameterNode> m_next;
     };
 
-    class ScopeNode : public BlockNode {
+    struct ScopeNodeData {
+        typedef DeclarationStacks::VarStack VarStack;
+        typedef DeclarationStacks::FunctionStack FunctionStack;
+
+        ScopeNodeData(SourceElements*, VarStack*, FunctionStack*, int numConstants);
+
+        VarStack m_varStack;
+        FunctionStack m_functionStack;
+        int m_numConstants;
+        StatementVector m_children;
+    };
+
+    class ScopeNode : public StatementNode {
     public:
         typedef DeclarationStacks::VarStack VarStack;
         typedef DeclarationStacks::FunctionStack FunctionStack;
 
+        ScopeNode(JSGlobalData*) JSC_FAST_CALL;
         ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL;
+        virtual ~ScopeNode();
+        virtual void releaseNodes(NodeReleaser&);
+
+        void adoptData(std::auto_ptr<ScopeNodeData> data) { m_data.adopt(data); }
+        ScopeNodeData* data() const { return m_data.get(); }
+        void destroyData() { m_data.clear(); }
 
         const SourceCode& source() const { return m_source; }
         const UString& sourceURL() const JSC_FAST_CALL { return m_source.provider()->url(); }
         intptr_t sourceID() const { return m_source.provider()->asID(); }
 
+        void setFeatures(CodeFeatures features) { m_features = features; }
         bool usesEval() const { return m_features & EvalFeature; }
         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); }
 
-        VarStack& varStack() { return m_varStack; }
-        FunctionStack& functionStack() { return m_functionStack; }
+        VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; }
+        FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; }
+
+        StatementVector& children() { ASSERT(m_data); return m_data->m_children; }
 
         int neededConstants()
         {
+            ASSERT(m_data);
             // We may need 2 more constants than the count given by the parser,
             // because of the various uses of jsUndefined() and jsNull().
-            return m_numConstants + 2;
+            return m_data->m_numConstants + 2;
         }
 
     protected:
         void setSource(const SourceCode& source) { m_source = source; }
 
-        VarStack m_varStack;
-        FunctionStack m_functionStack;
-
     private:
-        SourceCode m_source;
+        OwnPtr<ScopeNodeData> m_data;
         CodeFeatures m_features;
-        int m_numConstants;
+        SourceCode m_source;
     };
 
     class ProgramNode : public ScopeNode {
@@ -2141,9 +2167,9 @@ namespace JSC {
     class FunctionBodyNode : public ScopeNode {
         friend class JIT;
     public:
+        static FunctionBodyNode* create(JSGlobalData*) JSC_FAST_CALL;
         static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
-        static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL;
-        ~FunctionBodyNode();
+        virtual ~FunctionBodyNode();
 
         const Identifier* parameters() const JSC_FAST_CALL { return m_parameters; }
         size_t parameterCount() const { return m_parameterCount; }
@@ -2193,6 +2219,7 @@ namespace JSC {
         }
 
     private:
+        FunctionBodyNode(JSGlobalData*) JSC_FAST_CALL;
         FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
 
         void generateBytecode(ScopeChainNode*) JSC_FAST_CALL;
@@ -2217,6 +2244,8 @@ namespace JSC {
         virtual ~FuncExprNode();
         virtual void releaseNodes(NodeReleaser&);
 
+        virtual bool isFuncExprNode() const JSC_FAST_CALL { return true; } 
+
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
         JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL;
 
index 51ffaf6..a906169 100644 (file)
@@ -63,6 +63,28 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
     }
 }
 
+void Parser::reparse(JSGlobalData* globalData, FunctionBodyNode* functionBodyNode)
+{
+    ASSERT(!functionBodyNode->data());
+
+    m_source = &functionBodyNode->source();
+    parse(globalData, 0, 0);
+    ASSERT(m_sourceElements);
+    functionBodyNode->adoptData(auto_ptr<ScopeNodeData>(new ScopeNodeData(m_sourceElements.get(),
+                                                                          m_varDeclarations ? &m_varDeclarations->data : 0, 
+                                                                          m_funcDeclarations ? &m_funcDeclarations->data : 0,
+                                                                          m_numConstants)));
+    bool usesArguments = functionBodyNode->usesArguments();
+    functionBodyNode->setFeatures(m_features);
+    if (usesArguments && !functionBodyNode->usesArguments())
+        functionBodyNode->setUsesArguments();
+
+    m_source = 0;
+    m_sourceElements = 0;
+    m_varDeclarations = 0;
+    m_funcDeclarations = 0;
+}
+
 void Parser::didFinishParsing(SourceElements* sourceElements, ParserRefCountedData<DeclarationStacks::VarStack>* varStack, 
                               ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants)
 {
index 2b00dc9..c2d186f 100644 (file)
@@ -51,6 +51,8 @@ namespace JSC {
     public:
         template <class ParsedNode> PassRefPtr<ParsedNode> parse(ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
 
+        void reparse(JSGlobalData*, FunctionBodyNode*);
+
         void didFinishParsing(SourceElements*, ParserRefCountedData<DeclarationStacks::VarStack>*, 
                               ParserRefCountedData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants);
 
index 2840161..84360b8 100644 (file)
@@ -70,6 +70,7 @@ namespace JSC {
         SourceProvider* provider() const { return m_provider.get(); }
         int firstLine() const { return m_firstLine; }
         int startOffset() const { return m_startChar; }
+        int endOffset() const { return m_endChar; }
         const UChar* data() const { return m_provider->data() + m_startChar; }
         int length() const { return m_endChar - m_startChar; }
 
index 059d5b7..17fce67 100644 (file)
@@ -66,75 +66,57 @@ CallType FunctionConstructor::getCallData(CallData& callData)
     return CallTypeHost;
 }
 
+static FunctionBodyNode* functionBody(ProgramNode* program)
+{
+    if (!program)
+        return 0;
+
+    StatementVector& children = program->children();
+    if (children.size() != 1)
+        return 0;
+
+    ExprStatementNode* exprStatement = static_cast<ExprStatementNode*>(children[0].get()); 
+    ASSERT(exprStatement->isExprStatement());
+    if (!exprStatement || !exprStatement->isExprStatement())
+        return 0;
+
+    FuncExprNode* funcExpr = static_cast<FuncExprNode*>(exprStatement->expr());
+    ASSERT(funcExpr->isFuncExprNode());
+    if (!funcExpr || !funcExpr->isFuncExprNode())
+        return 0;
+
+    FunctionBodyNode* body = funcExpr->body();
+    ASSERT(body);
+    return body;
+}
+
 // ECMA 15.3.2 The Function Constructor
 JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
 {
-    UString p("");
-    UString body;
-    int argsSize = args.size();
-    if (argsSize == 0)
-        body = "";
-    else if (argsSize == 1)
-        body = args.at(exec, 0)->toString(exec);
+    UString program;
+    if (args.isEmpty())
+        program = "(function(){})";
+    else if (args.size() == 1)
+        program = "(function(){" + args.at(exec, 0)->toString(exec) + "})";
     else {
-        p = args.at(exec, 0)->toString(exec);
-        for (int k = 1; k < argsSize - 1; k++)
-            p += "," + args.at(exec, k)->toString(exec);
-        body = args.at(exec, argsSize - 1)->toString(exec);
+        program = "(function(" + args.at(exec, 0)->toString(exec);
+        for (size_t i = 1; i < args.size() - 1; i++)
+            program += "," + args.at(exec, i)->toString(exec);
+        program += "){" + args.at(exec, args.size() - 1)->toString(exec) + "})";
     }
 
-    // parse the source code
     int errLine;
     UString errMsg;
-    SourceCode source = makeSource(body, sourceURL, lineNumber);
-    RefPtr<FunctionBodyNode> functionBody = exec->globalData().parser->parse<FunctionBodyNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg);
+    SourceCode source = makeSource(program, sourceURL, lineNumber);
+    RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg);
 
-    // No program node == syntax error - throw a syntax error
-    if (!functionBody)
-        // We can't return a Completion(Throw) here, so just set the exception
-        // and return it
+    FunctionBodyNode* body = functionBody(programNode.get());
+    if (!body)
         return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url());
 
-    // parse parameter list. throw syntax error on illegal identifiers
-    int len = p.size();
-    const UChar* c = p.data();
-    int i = 0;
-    UString param;
-    Vector<Identifier> parameters;
-    while (i < len) {
-        while (*c == ' ' && i < len)
-            c++, i++;
-        if (Lexer::isIdentStart(c[0])) {  // else error
-            param = UString(c, 1);
-            c++, i++;
-            while (i < len && (Lexer::isIdentPart(c[0]))) {
-                param.append(*c);
-                c++, i++;
-            }
-            while (i < len && *c == ' ')
-                c++, i++;
-            if (i == len) {
-                parameters.append(Identifier(exec, param));
-                break;
-            } else if (*c == ',') {
-                parameters.append(Identifier(exec, param));
-                c++, i++;
-                continue;
-            } // else error
-        }
-        return throwError(exec, SyntaxError, "Syntax error in parameter list");
-    }
-    size_t count = parameters.size();
-    functionBody->finishParsing(parameters.releaseBuffer(), count);
-
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     ScopeChain scopeChain(globalObject, globalObject->globalData(), exec->globalThisValue());
-    JSFunction* function = new (exec) JSFunction(exec, functionName, functionBody.get(), scopeChain.node());
-
-    JSObject* prototype = constructEmptyObject(exec);
-    prototype->putDirect(exec->propertyNames().constructor, function, DontEnum);
-    function->putDirect(exec->propertyNames().prototype, prototype, DontDelete);
-    return function;
+    return new (exec) JSFunction(exec, functionName, body, scopeChain.node());
 }
 
 // ECMA 15.3.2 The Function Constructor
index a2bc0b6..23de221 100644 (file)
@@ -68,6 +68,7 @@ namespace JSC {
         friend bool operator!=(const Identifier&, const Identifier&);
 
         friend bool operator==(const Identifier&, const char*);
+        friend bool operator!=(const Identifier&, const char*);
     
         static void remove(UString::Rep*);
 
@@ -132,6 +133,11 @@ namespace JSC {
         return Identifier::equal(a, b);
     }
 
+    inline bool operator!=(const Identifier& a, const char* b)
+    {
+        return !Identifier::equal(a, b);
+    }
+
     IdentifierTable* createIdentifierTable();
     void deleteIdentifierTable(IdentifierTable*);