Reviewed by Anders.
authormjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 15 Mar 2006 10:21:48 +0000 (10:21 +0000)
committermjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 15 Mar 2006 10:21:48 +0000 (10:21 +0000)
        - KJS::Node and KJS::StatementNode are bigger than they need to be
        http://bugzilla.opendarwin.org/show_bug.cgi?id=7775

        The memory usage of Node was reduced by 2 machine words per node:

        - sourceURL was removed and only kept on FunctionBodyNode. The
        source URL can only be distinct per function or top-level program node,
        and you always have one.

        - refcount was removed and kept in a separate hashtable when
        greater than 1. newNodes set represents floating nodes with
        refcount of 0. This helps because almost all nodes have a refcount of 1
        for almost all of their lifetime.

        * bindings/runtime_method.cpp:
        (RuntimeMethod::RuntimeMethod): Pass null body, added FIXME.
        * kjs/Parser.cpp:
        (KJS::clearNewNodes): New nodes are tracked in nodes.cpp now, but still clear
        them at the appropriate time.
        * kjs/context.h:
        (KJS::ContextImp::currentBody): added; used to retrieve source URL and sid
        for current code.
        (KJS::ContextImp::pushIteration): moved here from LabelStack
        (KJS::ContextImp::popIteration): ditto
        (KJS::ContextImp::inIteration): ditto
        (KJS::ContextImp::pushSwitch): ditto
        (KJS::ContextImp::popSwitch): ditto
        (KJS::ContextImp::inSwitch): ditto
        * kjs/function.cpp:
        (KJS::FunctionImp::FunctionImp): Add FunctionBodyNode* parameter.
        (KJS::FunctionImp::callAsFunction): Pass body to ContextImp.
        (KJS::FunctionImp::argumentsGetter): _context renamed to m_context.
        (KJS::DeclaredFunctionImp::DeclaredFunctionImp): Pass body to superclass
        constructor.
        (KJS::GlobalFuncImp::callAsFunction): Pass progNode as body for ContextImp in
        eval.
        * kjs/function.h: Move body field from DeclaredFunctionImp to
        FunctionImp.
        * kjs/grammar.y: Change DBG; statements no longer have a sourceid.
        * kjs/internal.cpp:
        (KJS::ContextImp::ContextImp): Initialize new m_currentBody, m_iterationDepth
        and m_switchDepth data members. New FunctionBodyNode* parameter - the
        function body provides source URL and SourceId.
        (KJS::InterpreterImp::mark): Use exception() function, not _exception directly.
        (KJS::InterpreterImp::evaluate): Pass progNode to ContextImp constructor
        to use as the body.
        * kjs/internal.h:
        (KJS::LabelStack::LabelStack): Remove iteration depth and switch depth;
        statement label stacks don't need these and it bloats their size. Put them
        in the ContextImp instead.
        * kjs/interpreter.cpp:
        (KJS::ExecState::lexicalInterpreter): Renamed _context to m_context.
        * kjs/interpreter.h:
        (KJS::ExecState::dynamicInterpreter): Renamed _context to m_context.
        (KJS::ExecState::context): ditto
        (KJS::ExecState::setException): Renamed _exception to m_exception
        (KJS::ExecState::clearException): ditto
        (KJS::ExecState::exception): ditto
        (KJS::ExecState::hadException): ditto
        (KJS::ExecState::ExecState): ditto both above renames
        * kjs/nodes.cpp:
        (Node::Node): Removed initialization of line, source URL and refcount. Add to
        local newNodes set instead of involving parser.
        (Node::ref): Instead of managing refcount directly, story refcount over 1 in a
        HashCountedSet, and keep a separate HashSet of "floating" nodes with refcount
        0.
        (Node::deref): ditto
        (Node::refcount): ditto
        (Node::clearNewNodes): Destroy anything left in the new nodes set.
        (currentSourceId): Inline helper to get sourceId from function body via context.
        (currentSourceURL): ditto for sourceURL.
        (Node::createErrorCompletion): use new helper
        (Node::throwError): ditto
        (Node::setExceptionDetailsIfNeeded): ditto
        (StatementNode::StatementNode): remove initialization of l0 and sid, rename
        l1 to m_lastLine.
        (StatementNode::setLoc): Set own m_lastLine and Node's m_line.
        (StatementNode::hitStatement): Get sid, first line, last line in the proper new ways.
        (StatListNode::StatListNode): updated for setLoc changes
        (BlockNode::BlockNode): ditto
        (DoWhileNode::execute): excpect iteraton counts on ContextImp, not LabelStack
        (WhileNode::execute): ditto
        (ForNode::execute): ditto
        (ForInNode::execute): ditto
        (ContinueNode::execute): excpect inIteration on ContextImp, not LabelStack
        (BreakNode::execute): excpect inIteration and inSwitch on ContextImp, not LabelStack
        (SwitchNode::execute): expect switch counts on ContextImp, not LabelStack
        (FunctionBodyNode::FunctionBodyNode): update for new setLoc
        (FunctionBodyNode::processFuncDecl): reindent
        (SourceElementsNode::SourceElementsNode): update for new setLoc
        * kjs/nodes.h:
        (KJS::Node::lineNo): Renamed _line to m_line
        (KJS::StatementNode::firstLine): Use lineNo()
        (KJS::StatementNode::lastLine): Renamed l1 to m_lastLine
        (KJS::FunctionBodyNode::sourceId): added
        (KJS::FunctionBodyNode::sourceURL): added
        * kjs/testkjs.cpp:

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

13 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/bindings/runtime_method.cpp
JavaScriptCore/kjs/Parser.cpp
JavaScriptCore/kjs/context.h
JavaScriptCore/kjs/function.cpp
JavaScriptCore/kjs/function.h
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/internal.cpp
JavaScriptCore/kjs/internal.h
JavaScriptCore/kjs/interpreter.cpp
JavaScriptCore/kjs/interpreter.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h

index d282a28179facbecb30e76915e1a2a00c2c51329..ac484d01f19efa66f5a81104cecae65331ee0cf0 100644 (file)
@@ -1,3 +1,105 @@
+2006-03-13  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Anders.
+        
+        - KJS::Node and KJS::StatementNode are bigger than they need to be
+        http://bugzilla.opendarwin.org/show_bug.cgi?id=7775
+
+        The memory usage of Node was reduced by 2 machine words per node:
+
+        - sourceURL was removed and only kept on FunctionBodyNode. The
+        source URL can only be distinct per function or top-level program node, 
+        and you always have one.
+        
+        - refcount was removed and kept in a separate hashtable when
+        greater than 1. newNodes set represents floating nodes with
+        refcount of 0. This helps because almost all nodes have a refcount of 1
+        for almost all of their lifetime.
+        
+        * bindings/runtime_method.cpp:
+        (RuntimeMethod::RuntimeMethod): Pass null body, added FIXME.
+        * kjs/Parser.cpp:
+        (KJS::clearNewNodes): New nodes are tracked in nodes.cpp now, but still clear
+        them at the appropriate time.
+        * kjs/context.h:
+        (KJS::ContextImp::currentBody): added; used to retrieve source URL and sid
+        for current code.
+        (KJS::ContextImp::pushIteration): moved here from LabelStack
+        (KJS::ContextImp::popIteration): ditto
+        (KJS::ContextImp::inIteration): ditto
+        (KJS::ContextImp::pushSwitch): ditto
+        (KJS::ContextImp::popSwitch): ditto
+        (KJS::ContextImp::inSwitch): ditto
+        * kjs/function.cpp:
+        (KJS::FunctionImp::FunctionImp): Add FunctionBodyNode* parameter.
+        (KJS::FunctionImp::callAsFunction): Pass body to ContextImp.
+        (KJS::FunctionImp::argumentsGetter): _context renamed to m_context.
+        (KJS::DeclaredFunctionImp::DeclaredFunctionImp): Pass body to superclass
+        constructor.
+        (KJS::GlobalFuncImp::callAsFunction): Pass progNode as body for ContextImp in
+        eval.
+        * kjs/function.h: Move body field from DeclaredFunctionImp to
+        FunctionImp.
+        * kjs/grammar.y: Change DBG; statements no longer have a sourceid.
+        * kjs/internal.cpp:
+        (KJS::ContextImp::ContextImp): Initialize new m_currentBody, m_iterationDepth
+        and m_switchDepth data members. New FunctionBodyNode* parameter - the
+        function body provides source URL and SourceId.
+        (KJS::InterpreterImp::mark): Use exception() function, not _exception directly.
+        (KJS::InterpreterImp::evaluate): Pass progNode to ContextImp constructor
+        to use as the body.
+        * kjs/internal.h:
+        (KJS::LabelStack::LabelStack): Remove iteration depth and switch depth;
+        statement label stacks don't need these and it bloats their size. Put them
+        in the ContextImp instead.
+        * kjs/interpreter.cpp:
+        (KJS::ExecState::lexicalInterpreter): Renamed _context to m_context.
+        * kjs/interpreter.h:
+        (KJS::ExecState::dynamicInterpreter): Renamed _context to m_context.
+        (KJS::ExecState::context): ditto
+        (KJS::ExecState::setException): Renamed _exception to m_exception
+        (KJS::ExecState::clearException): ditto
+        (KJS::ExecState::exception): ditto
+        (KJS::ExecState::hadException): ditto
+        (KJS::ExecState::ExecState): ditto both above renames
+        * kjs/nodes.cpp:
+        (Node::Node): Removed initialization of line, source URL and refcount. Add to
+        local newNodes set instead of involving parser.
+        (Node::ref): Instead of managing refcount directly, story refcount over 1 in a
+        HashCountedSet, and keep a separate HashSet of "floating" nodes with refcount
+        0.
+        (Node::deref): ditto
+        (Node::refcount): ditto
+        (Node::clearNewNodes): Destroy anything left in the new nodes set.
+        (currentSourceId): Inline helper to get sourceId from function body via context.
+        (currentSourceURL): ditto for sourceURL.
+        (Node::createErrorCompletion): use new helper
+        (Node::throwError): ditto
+        (Node::setExceptionDetailsIfNeeded): ditto
+        (StatementNode::StatementNode): remove initialization of l0 and sid, rename
+        l1 to m_lastLine.
+        (StatementNode::setLoc): Set own m_lastLine and Node's m_line.
+        (StatementNode::hitStatement): Get sid, first line, last line in the proper new ways.
+        (StatListNode::StatListNode): updated for setLoc changes
+        (BlockNode::BlockNode): ditto
+        (DoWhileNode::execute): excpect iteraton counts on ContextImp, not LabelStack
+        (WhileNode::execute): ditto
+        (ForNode::execute): ditto
+        (ForInNode::execute): ditto
+        (ContinueNode::execute): excpect inIteration on ContextImp, not LabelStack
+        (BreakNode::execute): excpect inIteration and inSwitch on ContextImp, not LabelStack
+        (SwitchNode::execute): expect switch counts on ContextImp, not LabelStack
+        (FunctionBodyNode::FunctionBodyNode): update for new setLoc
+        (FunctionBodyNode::processFuncDecl): reindent
+        (SourceElementsNode::SourceElementsNode): update for new setLoc
+        * kjs/nodes.h:
+        (KJS::Node::lineNo): Renamed _line to m_line
+        (KJS::StatementNode::firstLine): Use lineNo()
+        (KJS::StatementNode::lastLine): Renamed l1 to m_lastLine
+        (KJS::FunctionBodyNode::sourceId): added
+        (KJS::FunctionBodyNode::sourceURL): added
+        * kjs/testkjs.cpp:
+
 2006-03-14  Geoffrey Garen  <ggaren@apple.com>
 
         - Fixed <rdar://problem/4478239> string sort puts "closed" before 
index b6fcfd18aa86053562f762576e0d992dd01d0af6..b380fef9af8223d20e192e79802ff9aa3b20f664 100644 (file)
@@ -32,7 +32,9 @@
 using namespace KJS::Bindings;
 using namespace KJS;
 
-RuntimeMethod::RuntimeMethod(ExecState *exec, const Identifier &ident, Bindings::MethodList &m) : FunctionImp (exec, ident)
+// FIXME: this should probably use InternalFunctionImp, not FunctionImp
+RuntimeMethod::RuntimeMethod(ExecState *exec, const Identifier &ident, Bindings::MethodList &m) 
+    : FunctionImp (exec, ident, 0)
 {
     _methodList = m;
 }
index 530f97cfa7760ad05476d4fd6442466d57ce8233..1692ef6893103e2549d76909f5a4691bd4bfd0da 100644 (file)
@@ -37,16 +37,8 @@ namespace KJS {
 int Parser::sid = 0;
 
 static RefPtr<ProgramNode>* progNode;
-static Vector<RefPtr<Node> >* newNodes;
 static HashSet<Node*>* nodeCycles;
 
-void Parser::saveNewNode(Node *node)
-{
-    if (!newNodes)
-        newNodes = new Vector<RefPtr<Node> >;
-    newNodes->append(node);
-}
-
 void Parser::noteNodeCycle(Node *node)
 {
     if (!nodeCycles)
@@ -68,9 +60,7 @@ static void clearNewNodes()
         delete nodeCycles;
         nodeCycles = 0;
     }
-
-    delete newNodes;
-    newNodes = 0;
+    Node::clearNewNodes();
 }
 
 PassRefPtr<ProgramNode> Parser::parse(const UString& sourceURL, int startingLineNumber,
index 05187ba8c937d5a71535535933f67db8610d73a8..c48a6042a654deeef75ea56ceda88b6e8e31ebdb 100644 (file)
@@ -35,10 +35,12 @@ namespace KJS  {
    */
   class ContextImp {
   public:
-    ContextImp(JSObject *glob, InterpreterImp *, JSObject *thisV, CodeType type = GlobalCode,
-               ContextImp *callingContext = 0, FunctionImp *functiion = 0, const List *args = 0);
+    ContextImp(JSObject* global, InterpreterImp*, JSObject* thisV, FunctionBodyNode* currentBody,
+               CodeType type = GlobalCode, ContextImp* callingContext = 0, FunctionImp* function = 0, const List* args = 0);
     ~ContextImp();
 
+    FunctionBodyNode* currentBody() { return m_currentBody; }
+
     const ScopeChain &scopeChain() const { return scope; }
     CodeType codeType() { return m_codeType; }
     JSObject *variableObject() const { return variable; }
@@ -52,12 +54,23 @@ namespace KJS  {
     void pushScope(JSObject *s) { scope.push(s); }
     void popScope() { scope.pop(); }
     LabelStack *seenLabels() { return &ls; }
+
+
+    void pushIteration() { m_iterationDepth++; }
+    void popIteration() { m_iterationDepth--; }
+    bool inIteration() const { return (m_iterationDepth > 0); }
     
+    void pushSwitch() { m_switchDepth++; }
+    void popSwitch() { m_switchDepth--; }
+    bool inSwitch() const { return (m_switchDepth > 0); }
+        
     void mark();
 
   private:
     InterpreterImp *_interpreter;
     ContextImp *_callingContext;
+    FunctionBodyNode* m_currentBody;
+
     FunctionImp *_function;
     const List *_arguments;
     // because ContextImp is always allocated on the stack,
@@ -70,6 +83,8 @@ namespace KJS  {
     JSObject *thisVal;
 
     LabelStack ls;
+    int m_iterationDepth;
+    int m_switchDepth;
     CodeType m_codeType;
   };
 
index 68226d6e8fdfe9f9b2e5f0620187ba82799c6114..a3943b2b480d0149130a23944db601821eabe5b0 100644 (file)
@@ -55,9 +55,10 @@ const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0,
     OwnPtr<Parameter> next;
   };
 
-FunctionImp::FunctionImp(ExecState *exec, const Identifier &n)
+FunctionImp::FunctionImp(ExecState *exec, const Identifier &n, FunctionBodyNode* b)
   : InternalFunctionImp(static_cast<FunctionPrototype*>
                         (exec->lexicalInterpreter()->builtinFunctionPrototype()), n)
+  , body(b)
 {
 }
 
@@ -65,13 +66,13 @@ FunctionImp::~FunctionImp()
 {
 }
 
-JSValue *FunctionImp::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
+JSValue *FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
 {
   JSObject *globalObj = exec->dynamicInterpreter()->globalObject();
 
   // enter a new execution context
-  ContextImp ctx(globalObj, exec->dynamicInterpreter()->imp(), thisObj, codeType(),
-                 exec->context().imp(), this, &args);
+  ContextImp ctx(globalObj, exec->dynamicInterpreter()->imp(), thisObj, body.get(),
+                 codeType(), exec->context().imp(), this, &args);
   ExecState newExec(exec->dynamicInterpreter(), &ctx);
   newExec.setException(exec->exception()); // could be null
 
@@ -202,7 +203,7 @@ void FunctionImp::processVarDecls(ExecState */*exec*/)
 JSValue *FunctionImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
 {
   FunctionImp *thisObj = static_cast<FunctionImp *>(slot.slotBase());
-  ContextImp *context = exec->_context;
+  ContextImp *context = exec->m_context;
   while (context) {
     if (context->function() == thisObj) {
       return static_cast<ActivationImp *>(context->activationObject())->get(exec, propertyName);
@@ -294,7 +295,7 @@ const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0,
 
 DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const Identifier &n,
                                         FunctionBodyNode *b, const ScopeChain &sc)
-  : FunctionImp(exec,n), body(b)
+  : FunctionImp(exec, n, b)
 {
   setScope(sc);
 }
@@ -803,6 +804,7 @@ JSValue *GlobalFuncImp::callAsFunction(ExecState *exec, JSObject */*thisObj*/, c
         ContextImp ctx(exec->dynamicInterpreter()->globalObject(),
                        exec->dynamicInterpreter()->imp(),
                        thisVal,
+                       progNode.get(),
                        EvalCode,
                        exec->context().imp());
         
index 93b363a8559d44f8fd4508ceaf028d7720e0a120..18bb3a00aed86383723c12302def16e4dc73b65e 100644 (file)
@@ -39,7 +39,7 @@ namespace KJS {
   class FunctionImp : public InternalFunctionImp {
     friend class ActivationImp;
   public:
-    FunctionImp(ExecState *exec, const Identifier &n = Identifier::null());
+    FunctionImp(ExecState* exec, const Identifier& n, FunctionBodyNode* b);
     virtual ~FunctionImp();
 
     virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
@@ -58,6 +58,9 @@ namespace KJS {
 
     virtual const ClassInfo *classInfo() const { return &info; }
     static const ClassInfo info;
+
+    RefPtr<FunctionBodyNode> body;
+
   protected:
     OwnPtr<Parameter> param;
 
@@ -79,10 +82,10 @@ namespace KJS {
 
     virtual Completion execute(ExecState *exec);
     CodeType codeType() const { return FunctionCode; }
-    RefPtr<FunctionBodyNode> body;
 
     virtual const ClassInfo *classInfo() const { return &info; }
     static const ClassInfo info;
+
   private:
     virtual void processVarDecls(ExecState *exec);
   };
index 94ab1c4b9dbbf24c9851c5da3794cd77f505faad..fdefaaf2114c324d9f9c0b82edb5cd2281d348da 100644 (file)
@@ -48,7 +48,7 @@ int kjsyyerror(const char *);
 static bool allowAutomaticSemicolon();
 
 #define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon()) YYABORT; } while (0)
-#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line, Parser::sid)
+#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
 
 using namespace KJS;
 
index 2d80696b13d76febe4a5e6ec59f523e98fa71347..e35ca94da9bb813d8a1402fc6b6f1d15cd0c6592 100644 (file)
@@ -188,9 +188,15 @@ bool LabelStack::contains(const Identifier &id) const
 // ------------------------------ ContextImp -----------------------------------
 
 // ECMA 10.2
-ContextImp::ContextImp(JSObject *glob, InterpreterImp *interpreter, JSObject *thisV, CodeType type,
-                       ContextImp *callingCon, FunctionImp *func, const List *args)
-    : _interpreter(interpreter), _function(func), _arguments(args)
+ContextImp::ContextImp(JSObject *glob, InterpreterImp *interpreter, JSObject *thisV, FunctionBodyNode* currentBody,
+                       
+                       CodeType type, ContextImp *callingCon, FunctionImp *func, const List *args)
+    : _interpreter(interpreter)
+    , m_currentBody(currentBody)
+    , _function(func)
+    , _arguments(args)
+    , m_iterationDepth(0)
+    , m_switchDepth(0) 
 {
   m_codeType = type;
   _callingContext = callingCon;
@@ -442,8 +448,8 @@ void InterpreterImp::mark()
     _context->mark();
   if (global)
       global->mark();
-  if (globExec._exception)
-      globExec._exception->mark();
+  if (globExec.exception())
+      globExec.exception()->mark();
 }
 
 bool InterpreterImp::checkSyntax(const UString &code)
@@ -497,7 +503,7 @@ Completion InterpreterImp::evaluate(const UChar* code, int codeLength, JSValue*
     res = Completion(Throw, globExec.exception());
   else {
     // execute the code
-    ContextImp ctx(globalObj, this, thisObj);
+    ContextImp ctx(globalObj, this, thisObj, progNode.get());
     ExecState newExec(m_interpreter, &ctx);
     progNode->processVarDecls(&newExec);
     res = progNode->execute(&newExec);
index 9c59a920f9f7284c990ef58e8dcbbee8622ee818..f38aa1c1dc01c6b26dedcebab353dbc4ce308c18 100644 (file)
@@ -93,7 +93,10 @@ namespace KJS {
    */
   class LabelStack : Noncopyable {
   public:
-    LabelStack(): tos(0), iterationDepth(0), switchDepth(0) {}
+    LabelStack()
+      : tos(0)
+    {
+    }
     ~LabelStack();
 
     /**
@@ -110,14 +113,6 @@ namespace KJS {
      */
     void pop();
     
-    void pushIteration() { iterationDepth++; }
-    void popIteration() { iterationDepth--; }
-    bool inIteration() const { return (iterationDepth > 0); }
-    
-    void pushSwitch() { switchDepth++; }
-    void popSwitch() { switchDepth--; }
-    bool inSwitch() const { return (switchDepth > 0); }
-    
   private:
     struct StackElem {
       Identifier id;
@@ -125,8 +120,6 @@ namespace KJS {
     };
 
     StackElem *tos;
-    int iterationDepth;
-    int switchDepth;
   };
 
 
index 640d635be52476da1c3f8b5e2d6e8db8ebba9ebe..131a597d21aaf504ad082926c3d4ef6768982a6f 100644 (file)
@@ -361,11 +361,11 @@ void Interpreter::virtual_hook( int, void* )
 
 Interpreter *ExecState::lexicalInterpreter() const
 {
-  if (!_context) {
+  if (!m_context) {
     return dynamicInterpreter();
   }
 
-  InterpreterImp *result = InterpreterImp::interpreterWithGlobalObject(_context->scopeChain().bottom());
+  InterpreterImp *result = InterpreterImp::interpreterWithGlobalObject(m_context->scopeChain().bottom());
 
   if (!result) {
     return dynamicInterpreter();
index 09cb35e58aa7ae380489db96b194815ed1267c72..b732a6b5080b3fc2fb67ebfb17c634f536bc144c 100644 (file)
@@ -444,7 +444,7 @@ namespace KJS {
      *
      * @return The interpreter executing the script
      */
-    Interpreter *dynamicInterpreter() const { return _interpreter; }
+    Interpreter *dynamicInterpreter() const { return m_interpreter; }
 
     // for compatibility
     Interpreter *interpreter() const { return dynamicInterpreter(); }
@@ -462,19 +462,23 @@ namespace KJS {
      *
      * @return The current execution state context
      */
-    Context context() const { return _context; }
+    Context context() const { return m_context; }
 
-    void setException(JSValue* e) { _exception = e; }
-    void clearException() { _exception = 0; }
-    JSValue* exception() const { return _exception; }
-    bool hadException() const { return _exception; }
+    void setException(JSValue* e) { m_exception = e; }
+    void clearException() { m_exception = 0; }
+    JSValue* exception() const { return m_exception; }
+    bool hadException() const { return m_exception; }
 
   private:
     ExecState(Interpreter* interp, ContextImp* con)
-        : _interpreter(interp), _context(con), _exception(0) { }
-    Interpreter* _interpreter;
-    ContextImp* _context;
-    JSValue* _exception;
+        : m_interpreter(interp)
+        , m_context(con)
+        , m_exception(0)
+    { 
+    }
+    Interpreter* m_interpreter;
+    ContextImp* m_context;
+    JSValue* m_exception;
   };
 
 } // namespace
index f38e7f619d0791f61024adb4c9b9eb74f99e8b76..3e1d7921780cd75402427c67d2f05c78577c4f4f 100644 (file)
@@ -44,6 +44,8 @@
 #include "operations.h"
 #include "ustring.h"
 #include "reference_list.h"
+#include <kxmlcore/HashSet.h>
+#include <kxmlcore/HashCountedSet.h>
 
 using namespace KJS;
 
@@ -95,16 +97,18 @@ int NodeCounter::count = 0;
 static NodeCounter nodeImplCounter;
 #endif NDEBUG
 
+static HashSet<Node*>* newNodes;
+static HashCountedSet<Node*>* nodeExtraRefCounts;
 
 Node::Node()
 {
 #ifndef NDEBUG
     ++NodeCounter::count;
 #endif
-  line = Lexer::curr()->lineNo();
-  sourceURL = Lexer::curr()->sourceURL();
-  m_refcount = 0;
-  Parser::saveNewNode(this);
+  m_line = Lexer::curr()->lineNo();
+  if (!newNodes)
+      newNodes = new HashSet<Node*>;
+  newNodes->add(this);
 }
 
 Node::~Node()
@@ -114,6 +118,51 @@ Node::~Node()
 #endif
 }
 
+void Node::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);
+            return;
+        }
+    }   
+    
+    if (!nodeExtraRefCounts)
+        nodeExtraRefCounts = new HashCountedSet<Node*>;
+    nodeExtraRefCounts->add(this);
+}
+
+void Node::deref()
+{
+    HashCountedSet<Node*>::iterator it = nodeExtraRefCounts->find(this);
+    if (it == nodeExtraRefCounts->end())
+        delete this;
+    else
+        nodeExtraRefCounts->remove(it);
+}
+
+unsigned int Node::refcount() 
+{
+    if (newNodes && newNodes->contains(this))
+        return 0;
+
+    if (!nodeExtraRefCounts)
+        return 1;
+
+    return 1 + nodeExtraRefCounts->count(this);
+}
+
+void Node::clearNewNodes()
+{
+    if (newNodes) {
+        deleteAllValues(*newNodes);
+        delete newNodes;
+        newNodes = 0;
+    }
+}
+
 static void substitute(UString &string, const UString &substring)
 {
     int position = string.find("%s");
@@ -121,21 +170,31 @@ static void substitute(UString &string, const UString &substring)
     string = string.substr(0, position) + substring + string.substr(position + 2);
 }
 
-Completion Node::createErrorCompletion(ExecState *exec, ErrorType e, const char *msg)
+static inline int currentSourceId(ExecState* exec)
 {
-    return Completion(Throw, Error::create(exec, e, msg, lineNo(), sourceId(), &sourceURL));
+    return exec->context().imp()->currentBody()->sourceId();
+}
+
+static inline const UString& currentSourceURL(ExecState* exec)
+{
+    return exec->context().imp()->currentBody()->sourceURL();
+}
+
+Completion Node::createErrorCompletion(ExecState* exec, ErrorType e, const char *msg)
+{
+    return Completion(Throw, Error::create(exec, e, msg, lineNo(), currentSourceId(exec), &currentSourceURL(exec)));
 }
 
 Completion Node::createErrorCompletion(ExecState *exec, ErrorType e, const char *msg, const Identifier &ident)
 {
     UString message = msg;
     substitute(message, ident.ustring());
-    return Completion(Throw, Error::create(exec, e, message, lineNo(), sourceId(), &sourceURL));
+    return Completion(Throw, Error::create(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec)));
 }
 
-JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg)
+JSValue *Node::throwError(ExecStateexec, ErrorType e, const char *msg)
 {
-    return KJS::throwError(exec, e, msg, lineNo(), sourceId(), &sourceURL);
+    return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
 }
 
 JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr)
@@ -143,7 +202,7 @@ JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue
     UString message = msg;
     substitute(message, v->toString(exec));
     substitute(message, expr->toString());
-    return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+    return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
 }
 
 
@@ -151,7 +210,7 @@ JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, const I
 {
     UString message = msg;
     substitute(message, label.ustring());
-    return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+    return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
 }
 
 JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *e1, Node *e2)
@@ -160,7 +219,7 @@ JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue
     substitute(message, v->toString(exec));
     substitute(message, e1->toString());
     substitute(message, e2->toString());
-    return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+    return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
 }
 
 JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, Node *expr, const Identifier &label)
@@ -169,7 +228,7 @@ JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue
     substitute(message, v->toString(exec));
     substitute(message, expr->toString());
     substitute(message, label.ustring());
-    return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+    return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
 }
 
 JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue *v, const Identifier &label)
@@ -177,7 +236,7 @@ JSValue *Node::throwError(ExecState *exec, ErrorType e, const char *msg, JSValue
     UString message = msg;
     substitute(message, v->toString(exec));
     substitute(message, label.ustring());
-    return KJS::throwError(exec, e, message, lineNo(), sourceId(), &sourceURL);
+    return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), &currentSourceURL(exec));
 }
 
 JSValue *Node::throwUndefinedVariableError(ExecState *exec, const Identifier &ident)
@@ -191,8 +250,8 @@ void Node::setExceptionDetailsIfNeeded(ExecState *exec)
     if (exceptionValue->isObject()) {
         JSObject *exception = static_cast<JSObject *>(exceptionValue);
         if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
-            exception->put(exec, "line", jsNumber(line));
-            exception->put(exec, "sourceURL", jsString(sourceURL));
+            exception->put(exec, "line", jsNumber(m_line));
+            exception->put(exec, "sourceURL", jsString(currentSourceURL(exec)));
         }
     }
 }
@@ -204,23 +263,24 @@ Node *Node::nodeInsideAllParens()
 
 // ------------------------------ StatementNode --------------------------------
 
-StatementNode::StatementNode() : l0(-1), l1(-1), sid(-1)
+StatementNode::StatementNode() 
+    : m_lastLine(-1)
 {
+    m_line = -1;
 }
 
-void StatementNode::setLoc(int line0, int line1, int sourceId)
+void StatementNode::setLoc(int firstLine, int lastLine)
 {
-    l0 = line0;
-    l1 = line1;
-    sid = sourceId;
+    m_line = firstLine;
+    m_lastLine = lastLine;
 }
 
 // return true if the debugger wants us to stop at this point
-bool StatementNode::hitStatement(ExecState *exec)
+bool StatementNode::hitStatement(ExecStateexec)
 {
   Debugger *dbg = exec->dynamicInterpreter()->imp()->debugger();
   if (dbg)
-    return dbg->atStatement(exec,sid,l0,l1);
+    return dbg->atStatement(exec, currentSourceId(exec), firstLine(), lastLine());
   else
     return true; // continue
 }
@@ -1442,14 +1502,14 @@ StatListNode::StatListNode(StatementNode *s)
   : statement(s), next(this)
 {
     Parser::noteNodeCycle(this);
-    setLoc(s->firstLine(), s->lastLine(), s->sourceId());
+    setLoc(s->firstLine(), s->lastLine());
 }
  
 StatListNode::StatListNode(StatListNode *l, StatementNode *s)
   : statement(s), next(l->next)
 {
   l->next = this;
-  setLoc(l->firstLine(), s->lastLine(), l->sourceId());
+  setLoc(l->firstLine(), s->lastLine());
 }
 
 // ECMA 12.1
@@ -1600,7 +1660,7 @@ BlockNode::BlockNode(SourceElementsNode *s)
     source = s->next;
     Parser::removeNodeCycle(source.get());
     s->next = 0;
-    setLoc(s->firstLine(), s->lastLine(), s->sourceId());
+    setLoc(s->firstLine(), s->lastLine());
   } else {
     source = 0;
   }
@@ -1689,9 +1749,9 @@ Completion DoWhileNode::execute(ExecState *exec)
     // bail out on error
     KJS_CHECKEXCEPTION
 
-    exec->context().imp()->seenLabels()->pushIteration();
+    exec->context().imp()->pushIteration();
     c = statement->execute(exec);
-    exec->context().imp()->seenLabels()->popIteration();
+    exec->context().imp()->popIteration();
     if (!((c.complType() == Continue) && ls.contains(c.target()))) {
       if ((c.complType() == Break) && ls.contains(c.target()))
         return Completion(Normal, 0);
@@ -1733,9 +1793,9 @@ Completion WhileNode::execute(ExecState *exec)
     if (!b)
       return Completion(Normal, value);
 
-    exec->context().imp()->seenLabels()->pushIteration();
+    exec->context().imp()->pushIteration();
     c = statement->execute(exec);
-    exec->context().imp()->seenLabels()->popIteration();
+    exec->context().imp()->popIteration();
     if (c.isValueCompletion())
       value = c.value();
 
@@ -1776,9 +1836,9 @@ Completion ForNode::execute(ExecState *exec)
     // bail out on error
     KJS_CHECKEXCEPTION
 
-    exec->context().imp()->seenLabels()->pushIteration();
+    exec->context().imp()->pushIteration();
     Completion c = statement->execute(exec);
-    exec->context().imp()->seenLabels()->popIteration();
+    exec->context().imp()->popIteration();
     if (c.isValueCompletion())
       cval = c.value();
     if (!((c.complType() == Continue) && ls.contains(c.target()))) {
@@ -1904,9 +1964,9 @@ Completion ForInNode::execute(ExecState *exec)
 
     KJS_CHECKEXCEPTION
 
-    exec->context().imp()->seenLabels()->pushIteration();
+    exec->context().imp()->pushIteration();
     c = statement->execute(exec);
-    exec->context().imp()->seenLabels()->popIteration();
+    exec->context().imp()->popIteration();
     if (c.isValueCompletion())
       retval = c.value();
 
@@ -1941,7 +2001,7 @@ Completion ContinueNode::execute(ExecState *exec)
 {
   KJS_BREAKPOINT;
 
-  if (ident.isEmpty() && !exec->context().imp()->seenLabels()->inIteration())
+  if (ident.isEmpty() && !exec->context().imp()->inIteration())
     return createErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
   else if (!ident.isEmpty() && !exec->context().imp()->seenLabels()->contains(ident))
     return createErrorCompletion(exec, SyntaxError, "Label %s not found.", ident);
@@ -1956,8 +2016,8 @@ Completion BreakNode::execute(ExecState *exec)
 {
   KJS_BREAKPOINT;
 
-  if (ident.isEmpty() && !exec->context().imp()->seenLabels()->inIteration() &&
-      !exec->context().imp()->seenLabels()->inSwitch())
+  if (ident.isEmpty() && !exec->context().imp()->inIteration() &&
+      !exec->context().imp()->inSwitch())
     return createErrorCompletion(exec, SyntaxError, "Invalid break statement.");
   else if (!ident.isEmpty() && !exec->context().imp()->seenLabels()->contains(ident))
     return createErrorCompletion(exec, SyntaxError, "Label %s not found.");
@@ -2171,9 +2231,9 @@ Completion SwitchNode::execute(ExecState *exec)
   JSValue *v = expr->evaluate(exec);
   KJS_CHECKEXCEPTION
 
-  exec->context().imp()->seenLabels()->pushSwitch();
+  exec->context().imp()->pushSwitch();
   Completion res = block->evalBlock(exec,v);
-  exec->context().imp()->seenLabels()->popSwitch();
+  exec->context().imp()->popSwitch();
 
   if ((res.complType() == Break) && ls.contains(res.target()))
     return Completion(Normal, res.value());
@@ -2269,15 +2329,18 @@ void ParameterNode::breakCycle()
 // ------------------------------ FunctionBodyNode -----------------------------
 
 FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
-  : BlockNode(s)
+    : BlockNode(s)
+    , m_sourceURL(Lexer::curr()->sourceURL())
+    , m_sourceId(Parser::sid)
 {
-  setLoc(-1, -1, -1);
+
+  setLoc(-1, -1);
 }
 
 void FunctionBodyNode::processFuncDecl(ExecState *exec)
 {
-  if (source)
-    source->processFuncDecl(exec);
+    if (source)
+        source->processFuncDecl(exec);
 }
 
 // ------------------------------ FuncDeclNode ---------------------------------
@@ -2362,14 +2425,14 @@ SourceElementsNode::SourceElementsNode(StatementNode *s1)
   : node(s1), next(this)
 {
     Parser::noteNodeCycle(this);
-    setLoc(s1->firstLine(), s1->lastLine(), s1->sourceId());
+    setLoc(s1->firstLine(), s1->lastLine());
 }
 
 SourceElementsNode::SourceElementsNode(SourceElementsNode *s1, StatementNode *s2)
   : node(s2), next(s1->next)
 {
   s1->next = this;
-  setLoc(s1->firstLine(), s2->lastLine(), s1->sourceId());
+  setLoc(s1->firstLine(), s2->lastLine());
 }
 
 // ECMA 14
index 82ebb18ff2bf0f676bb7559716357206405e109f..ffa177cbd0cfd8afb63e7fd077a9d82ed7301e49 100644 (file)
@@ -80,12 +80,12 @@ namespace KJS {
     UString toString() const;
     virtual void streamTo(SourceStream &s) const = 0;
     virtual void processVarDecls(ExecState *) {}
-    int lineNo() const { return line; }
+    int lineNo() const { return m_line; }
 
-    // reference counting mechanism
-    void ref() { ++m_refcount; }
-    void deref() { --m_refcount; if (!m_refcount) delete this; }
-    unsigned int refcount() { return m_refcount; }
+    void ref();
+    void deref();
+    unsigned int refcount();
+    static void clearNewNodes();
 
     virtual Node *nodeInsideAllParens();
 
@@ -112,11 +112,7 @@ namespace KJS {
 
     void setExceptionDetailsIfNeeded(ExecState *);
 
-    int line;
-    UString sourceURL;
-    unsigned int m_refcount;
-    virtual int sourceId() const { return -1; }
-
+    int m_line;
   private:
     // disallow assignment
     Node& operator=(const Node&);
@@ -126,10 +122,9 @@ namespace KJS {
   class StatementNode : public Node {
   public:
     StatementNode();
-    void setLoc(int line0, int line1, int sourceId);
-    int firstLine() const { return l0; }
-    int lastLine() const { return l1; }
-    int sourceId() const { return sid; }
+    void setLoc(int line0, int line1);
+    int firstLine() const { return lineNo(); }
+    int lastLine() const { return m_lastLine; }
     bool hitStatement(ExecState *exec);
     virtual Completion execute(ExecState *exec) = 0;
     void pushLabel(const Identifier &id) { ls.push(id); }
@@ -138,8 +133,7 @@ namespace KJS {
     LabelStack ls;
   private:
     JSValue *evaluate(ExecState */*exec*/) { return jsUndefined(); }
-    int l0, l1;
-    int sid;
+    int m_lastLine;
   };
 
   class NullNode : public Node {
@@ -1053,8 +1047,13 @@ namespace KJS {
   // inherited by ProgramNode
   class FunctionBodyNode : public BlockNode {
   public:
-    FunctionBodyNode(SourceElementsNode *s);
-    void processFuncDecl(ExecState *exec);
+    FunctionBodyNode(SourceElementsNode *);
+    virtual void processFuncDecl(ExecState *exec);
+    int sourceId() { return m_sourceId; }
+    const UString& sourceURL() { return m_sourceURL; }
+  private:
+    UString m_sourceURL;
+    int m_sourceId;
   };
 
   class FuncExprNode : public Node {