Reviewed by mjs.
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Dec 2005 11:16:11 +0000 (11:16 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 29 Dec 2005 11:16:11 +0000 (11:16 +0000)
        - Fixed <rdar://problem/4364705> run-javascriptcore-tests crashes in
        KJS::BlockNode::deref
        AKA
        http://bugzilla.opendarwin.org/show_bug.cgi?id=6233
        Reproducible stack-overflow crash in ~RefPtr<T> due to RefPtr<T> use in
        linked lists

        This patch does four things:
        (1) Standardizes all our linked list nodes to use "next" as their next
        pointers.
        (2) Creates the ListRefPtr<T> class, a subclass of RefPtr<T> specialized
        to iteratively deref "next" pointers.
        (3) Standardizes our linked list nodes to use ListRefPtr<T> and
        implement the releaseNext() function used by ~ListRefPtr<T>().
        (4) Adds to RefPtr<T> the release() method used by releaseNext().

        - Modified existing mozilla test to ensure it would make deployment
        builds crash as well.

        * JavaScriptCore.xcodeproj/project.pbxproj:
        * kjs/nodes.cpp:
        (ElementNode::evaluate):
        (PropertyListNode::evaluate):
        (ArgumentListNode::evaluateList):
        (StatListNode::StatListNode):
        (StatListNode::execute):
        (StatListNode::processVarDecls):
        (VarDeclListNode::evaluate):
        (VarDeclListNode::processVarDecls):
        (VarStatementNode::execute):
        (VarStatementNode::processVarDecls):
        (BlockNode::BlockNode):
        (CaseClauseNode::evalStatements):
        (CaseClauseNode::processVarDecls):
        (ClauseListNode::processVarDecls):
        (CaseBlockNode::CaseBlockNode):
        (CaseBlockNode::evalBlock):
        (SourceElementsNode::SourceElementsNode):
        (SourceElementsNode::execute):
        (SourceElementsNode::processFuncDecl):
        (SourceElementsNode::processVarDecls):
        * kjs/nodes.h:
        (KJS::ElementNode::ElementNode):
        (KJS::ElementNode::releaseNext):
        (KJS::ArrayNode::ArrayNode):
        (KJS::PropertyListNode::PropertyListNode):
        (KJS::PropertyListNode::releaseNext):
        (KJS::ObjectLiteralNode::ObjectLiteralNode):
        (KJS::ArgumentListNode::ArgumentListNode):
        (KJS::ArgumentListNode::releaseNext):
        (KJS::ArgumentsNode::ArgumentsNode):
        (KJS::StatListNode::releaseNext):
        (KJS::VarDeclListNode::VarDeclListNode):
        (KJS::VarDeclListNode::releaseNext):
        (KJS::VarStatementNode::VarStatementNode):
        (KJS::ForNode::ForNode):
        (KJS::CaseClauseNode::CaseClauseNode):
        (KJS::ClauseListNode::ClauseListNode):
        (KJS::ClauseListNode::getClause):
        (KJS::ClauseListNode::getNext):
        (KJS::ClauseListNode::releaseNext):
        (KJS::ParameterNode::ParameterNode):
        (KJS::ParameterNode::releaseNext):
        (KJS::SourceElementsNode::releaseNext):
        * kjs/nodes2string.cpp:
        (ElementNode::streamTo):
        (PropertyListNode::streamTo):
        (ArgumentListNode::streamTo):
        (StatListNode::streamTo):
        (VarDeclListNode::streamTo):
        (VarStatementNode::streamTo):
        (CaseClauseNode::streamTo):
        (ClauseListNode::streamTo):
        (CaseBlockNode::streamTo):
        (SourceElementsNode::streamTo):
        * kxmlcore/ListRefPtr.h: Added.
        (KXMLCore::ListRefPtr::ListRefPtr):
        (KXMLCore::ListRefPtr::~ListRefPtr):
        (KXMLCore::ListRefPtr::operator=):
        * kxmlcore/RefPtr.h:
        (KXMLCore::RefPtr::release):

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

JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/nodes2string.cpp
JavaScriptCore/kxmlcore/ListRefPtr.h [new file with mode: 0644]
JavaScriptCore/kxmlcore/RefPtr.h
JavaScriptCore/tests/mozilla/js1_5/Regress/regress-159334.js

index c739fbf5e0d35dc7c61c3bc9e824d480f6391545..815d2a2add8bb6c62bba490f4195bf7f7a32aa17 100644 (file)
@@ -1,3 +1,89 @@
+2005-12-26  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by mjs.
+
+        - Fixed <rdar://problem/4364705> run-javascriptcore-tests crashes in 
+        KJS::BlockNode::deref 
+        AKA 
+        http://bugzilla.opendarwin.org/show_bug.cgi?id=6233
+        Reproducible stack-overflow crash in ~RefPtr<T> due to RefPtr<T> use in 
+        linked lists
+
+        This patch does four things: 
+        (1) Standardizes all our linked list nodes to use "next" as their next 
+        pointers. 
+        (2) Creates the ListRefPtr<T> class, a subclass of RefPtr<T> specialized
+        to iteratively deref "next" pointers.
+        (3) Standardizes our linked list nodes to use ListRefPtr<T> and 
+        implement the releaseNext() function used by ~ListRefPtr<T>().
+        (4) Adds to RefPtr<T> the release() method used by releaseNext().
+
+        - Modified existing mozilla test to ensure it would make deployment 
+        builds crash as well.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * kjs/nodes.cpp:
+        (ElementNode::evaluate):
+        (PropertyListNode::evaluate):
+        (ArgumentListNode::evaluateList):
+        (StatListNode::StatListNode):
+        (StatListNode::execute):
+        (StatListNode::processVarDecls):
+        (VarDeclListNode::evaluate):
+        (VarDeclListNode::processVarDecls):
+        (VarStatementNode::execute):
+        (VarStatementNode::processVarDecls):
+        (BlockNode::BlockNode):
+        (CaseClauseNode::evalStatements):
+        (CaseClauseNode::processVarDecls):
+        (ClauseListNode::processVarDecls):
+        (CaseBlockNode::CaseBlockNode):
+        (CaseBlockNode::evalBlock):
+        (SourceElementsNode::SourceElementsNode):
+        (SourceElementsNode::execute):
+        (SourceElementsNode::processFuncDecl):
+        (SourceElementsNode::processVarDecls):
+        * kjs/nodes.h:
+        (KJS::ElementNode::ElementNode):
+        (KJS::ElementNode::releaseNext):
+        (KJS::ArrayNode::ArrayNode):
+        (KJS::PropertyListNode::PropertyListNode):
+        (KJS::PropertyListNode::releaseNext):
+        (KJS::ObjectLiteralNode::ObjectLiteralNode):
+        (KJS::ArgumentListNode::ArgumentListNode):
+        (KJS::ArgumentListNode::releaseNext):
+        (KJS::ArgumentsNode::ArgumentsNode):
+        (KJS::StatListNode::releaseNext):
+        (KJS::VarDeclListNode::VarDeclListNode):
+        (KJS::VarDeclListNode::releaseNext):
+        (KJS::VarStatementNode::VarStatementNode):
+        (KJS::ForNode::ForNode):
+        (KJS::CaseClauseNode::CaseClauseNode):
+        (KJS::ClauseListNode::ClauseListNode):
+        (KJS::ClauseListNode::getClause):
+        (KJS::ClauseListNode::getNext):
+        (KJS::ClauseListNode::releaseNext):
+        (KJS::ParameterNode::ParameterNode):
+        (KJS::ParameterNode::releaseNext):
+        (KJS::SourceElementsNode::releaseNext):
+        * kjs/nodes2string.cpp:
+        (ElementNode::streamTo):
+        (PropertyListNode::streamTo):
+        (ArgumentListNode::streamTo):
+        (StatListNode::streamTo):
+        (VarDeclListNode::streamTo):
+        (VarStatementNode::streamTo):
+        (CaseClauseNode::streamTo):
+        (ClauseListNode::streamTo):
+        (CaseBlockNode::streamTo):
+        (SourceElementsNode::streamTo):
+        * kxmlcore/ListRefPtr.h: Added.
+        (KXMLCore::ListRefPtr::ListRefPtr):
+        (KXMLCore::ListRefPtr::~ListRefPtr):
+        (KXMLCore::ListRefPtr::operator=):
+        * kxmlcore/RefPtr.h:
+        (KXMLCore::RefPtr::release):
+
 2005-12-29  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by mjs.
index 9a29fd073b9fd7e49a23abd5a9bbdc1bf693ea80..8638857e86b486f9999a7ac383c65a9b2e0d6033 100644 (file)
@@ -25,6 +25,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 148A1626095D16BB00666D0D /* ListRefPtr.h */; };
                652C107F08DA7B1E0020887D /* protected_reference.h in Headers */ = {isa = PBXBuildFile; fileRef = 652C107E08DA7B1E0020887D /* protected_reference.h */; };
                6541BD7208E80A17002CBEE7 /* TCPageMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 6541BD6E08E80A17002CBEE7 /* TCPageMap.h */; };
                6541BD7308E80A17002CBEE7 /* TCSpinLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 6541BD6F08E80A17002CBEE7 /* TCSpinLock.h */; };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+               148A1626095D16BB00666D0D /* ListRefPtr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ListRefPtr.h; sourceTree = "<group>"; };
                45E12D8806A49B0F00E9DF84 /* testkjs.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = testkjs.cpp; sourceTree = "<group>"; tabWidth = 8; };
                5114F47B05E4426200D1BBBD /* runtime_root.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = runtime_root.cpp; path = bindings/runtime_root.cpp; sourceTree = "<group>"; tabWidth = 8; };
                5114F47C05E4426200D1BBBD /* runtime_root.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = runtime_root.h; path = bindings/runtime_root.h; sourceTree = "<group>"; tabWidth = 8; };
                                657EEBBF094E445E008C9C7B /* HashCountedSet.h */,
                                65C647B3093EF8D60022C380 /* RefPtr.h */,
                                6580F795094070560082C219 /* PassRefPtr.h */,
+                               148A1626095D16BB00666D0D /* ListRefPtr.h */,
                                65D7D19B08F10B5B0015ABD8 /* FastMallocInternal.h */,
                                6557E8F708EA5D4D0049CDFC /* HashMapPtrSpec.h */,
                                65DFC92A08EA173A00F7300B /* HashFunctions.h */,
                                6580F796094070560082C219 /* PassRefPtr.h in Headers */,
                                657EEBC0094E445E008C9C7B /* HashCountedSet.h in Headers */,
                                93AA4F780957251F0084B3A7 /* AlwaysInline.h in Headers */,
+                               148A1627095D16BB00666D0D /* ListRefPtr.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 6ab9f983879164c04eb91e6620a708bab5e16032..df1756c590ccec11e81e59b839b758275fe1b1a4 100644 (file)
@@ -309,7 +309,7 @@ JSValue *ElementNode::evaluate(ExecState *exec)
 {
   JSObject *array = exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty());
   int length = 0;
-  for (ElementNode *n = this; n; n = n->list.get()) {
+  for (ElementNode *n = this; n; n = n->next.get()) {
     JSValue *val = n->node->evaluate(exec);
     KJS_CHECKEXCEPTIONVALUE
     length += n->elision;
@@ -360,7 +360,7 @@ JSValue *PropertyListNode::evaluate(ExecState *exec)
 {
   JSObject *obj = exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty());
   
-  for (PropertyListNode *p = this; p; p = p->list.get()) {
+  for (PropertyListNode *p = this; p; p = p->next.get()) {
     JSValue *n = p->node->name->evaluate(exec);
     KJS_CHECKEXCEPTIONVALUE
     JSValue *v = p->node->assign->evaluate(exec);
@@ -449,7 +449,7 @@ List ArgumentListNode::evaluateList(ExecState *exec)
 {
   List l;
 
-  for (ArgumentListNode *n = this; n; n = n->list.get()) {
+  for (ArgumentListNode *n = this; n; n = n->next.get()) {
     JSValue *v = n->expr->evaluate(exec);
     KJS_CHECKEXCEPTIONLIST
     l.append(v);
@@ -1415,15 +1415,15 @@ JSValue *CommaNode::evaluate(ExecState *exec)
 // ------------------------------ StatListNode ---------------------------------
 
 StatListNode::StatListNode(StatementNode *s)
-  : statement(s), list(this)
+  : statement(s), next(this)
 {
   setLoc(s->firstLine(), s->lastLine(), s->sourceId());
 }
  
 StatListNode::StatListNode(StatListNode *l, StatementNode *s)
-  : statement(s), list(l->list)
+  : statement(s), next(l->next)
 {
-  l->list = this;
+  l->next = this;
   setLoc(l->firstLine(), s->lastLine(), l->sourceId());
 }
 
@@ -1437,7 +1437,7 @@ Completion StatListNode::execute(ExecState *exec)
   
   JSValue *v = c.value();
   
-  for (StatListNode *n = list.get(); n; n = n->list.get()) {
+  for (StatListNode *n = next.get(); n; n = n->next.get()) {
     Completion c2 = n->statement->execute(exec);
     KJS_ABORTPOINT
     if (c2.complType() != Normal)
@@ -1453,7 +1453,7 @@ Completion StatListNode::execute(ExecState *exec)
 
 void StatListNode::processVarDecls(ExecState *exec)
 {
-  for (StatListNode *n = this; n; n = n->list.get())
+  for (StatListNode *n = this; n; n = n->next.get())
     n->statement->processVarDecls(exec);
 }
 
@@ -1526,7 +1526,7 @@ void VarDeclNode::processVarDecls(ExecState *exec)
 // ECMA 12.2
 JSValue *VarDeclListNode::evaluate(ExecState *exec)
 {
-  for (VarDeclListNode *n = this; n; n = n->list.get()) {
+  for (VarDeclListNode *n = this; n; n = n->next.get()) {
     n->var->evaluate(exec);
     KJS_CHECKEXCEPTIONVALUE
   }
@@ -1535,7 +1535,7 @@ JSValue *VarDeclListNode::evaluate(ExecState *exec)
 
 void VarDeclListNode::processVarDecls(ExecState *exec)
 {
-  for (VarDeclListNode *n = this; n; n = n->list.get())
+  for (VarDeclListNode *n = this; n; n = n->next.get())
     n->var->processVarDecls(exec);
 }
 
@@ -1546,7 +1546,7 @@ Completion VarStatementNode::execute(ExecState *exec)
 {
   KJS_BREAKPOINT;
 
-  (void) list->evaluate(exec);
+  (void) next->evaluate(exec);
   KJS_CHECKEXCEPTION
 
   return Completion(Normal);
@@ -1554,7 +1554,7 @@ Completion VarStatementNode::execute(ExecState *exec)
 
 void VarStatementNode::processVarDecls(ExecState *exec)
 {
-  list->processVarDecls(exec);
+  next->processVarDecls(exec);
 }
 
 // ------------------------------ BlockNode ------------------------------------
@@ -1562,8 +1562,8 @@ void VarStatementNode::processVarDecls(ExecState *exec)
 BlockNode::BlockNode(SourceElementsNode *s)
 {
   if (s) {
-    source = s->elements;
-    s->elements = 0;
+    source = s->next;
+    s->next = 0;
     setLoc(s->firstLine(), s->lastLine(), s->sourceId());
   } else {
     source = 0;
@@ -1984,16 +1984,16 @@ JSValue *CaseClauseNode::evaluate(ExecState *exec)
 // ECMA 12.11
 Completion CaseClauseNode::evalStatements(ExecState *exec)
 {
-  if (list)
-    return list->execute(exec);
+  if (next)
+    return next->execute(exec);
   else
     return Completion(Normal, jsUndefined());
 }
 
 void CaseClauseNode::processVarDecls(ExecState *exec)
 {
-  if (list)
-    list->processVarDecls(exec);
+  if (next)
+    next->processVarDecls(exec);
 }
 
 // ------------------------------ ClauseListNode -------------------------------
@@ -2008,9 +2008,9 @@ JSValue *ClauseListNode::evaluate(ExecState *)
 // ECMA 12.11
 void ClauseListNode::processVarDecls(ExecState *exec)
 {
-  for (ClauseListNode *n = this; n; n = n->nx.get())
-    if (n->cl)
-      n->cl->processVarDecls(exec);
+  for (ClauseListNode *n = this; n; n = n->next.get())
+    if (n->clause)
+      n->clause->processVarDecls(exec);
 }
 
 // ------------------------------ CaseBlockNode --------------------------------
@@ -2019,8 +2019,8 @@ CaseBlockNode::CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d,
                              ClauseListNode *l2)
 {
   if (l1) {
-    list1 = l1->nx;
-    l1->nx = 0;
+    list1 = l1->next;
+    l1->next = 0;
   } else {
     list1 = 0;
   }
@@ -2028,8 +2028,8 @@ CaseBlockNode::CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d,
   def = d;
 
   if (l2) {
-    list2 = l2->nx;
-    l2->nx = 0;
+    list2 = l2->next;
+    l2->next = 0;
   } else {
     list2 = 0;
   }
@@ -2052,8 +2052,8 @@ Completion CaseBlockNode::evalBlock(ExecState *exec, JSValue *input)
   CaseClauseNode *clause;
 
     while (a) {
-      clause = a->clause();
-      a = a->next();
+      clause = a->getClause();
+      a = a->getNext();
       v = clause->evaluate(exec);
       KJS_CHECKEXCEPTION
       if (strictEqual(exec, input, v)) {
@@ -2061,18 +2061,18 @@ Completion CaseBlockNode::evalBlock(ExecState *exec, JSValue *input)
        if (res.complType() != Normal)
          return res;
        while (a) {
-         res = a->clause()->evalStatements(exec);
+         res = a->getClause()->evalStatements(exec);
          if (res.complType() != Normal)
            return res;
-         a = a->next();
+         a = a->getNext();
        }
        break;
       }
     }
 
   while (b) {
-    clause = b->clause();
-    b = b->next();
+    clause = b->getClause();
+    b = b->getNext();
     v = clause->evaluate(exec);
     KJS_CHECKEXCEPTION
     if (strictEqual(exec, input, v)) {
@@ -2092,11 +2092,11 @@ Completion CaseBlockNode::evalBlock(ExecState *exec, JSValue *input)
   b = list2.get();
  step18:
   while (b) {
-    clause = b->clause();
+    clause = b->getClause();
     res = clause->evalStatements(exec);
     if (res.complType() != Normal)
       return res;
-    b = b->next();
+    b = b->getNext();
   }
 
   // bail out on error
@@ -2305,16 +2305,18 @@ JSValue *FuncExprNode::evaluate(ExecState *exec)
 
 // ------------------------------ SourceElementsNode ---------------------------
 
+int SourceElementsNode::count = 0;
+
 SourceElementsNode::SourceElementsNode(StatementNode *s1)
-  : element(s1), elements(this)
+  : node(s1), next(this)
 {
   setLoc(s1->firstLine(), s1->lastLine(), s1->sourceId());
 }
+
 SourceElementsNode::SourceElementsNode(SourceElementsNode *s1, StatementNode *s2)
-  : element(s2), elements(s1->elements)
+  : node(s2), next(s1->next)
 {
-  s1->elements = this;
+  s1->next = this;
   setLoc(s1->firstLine(), s2->lastLine(), s1->sourceId());
 }
 
@@ -2323,13 +2325,13 @@ Completion SourceElementsNode::execute(ExecState *exec)
 {
   KJS_CHECKEXCEPTION
 
-  Completion c1 = element->execute(exec);
+  Completion c1 = node->execute(exec);
   KJS_CHECKEXCEPTION;
   if (c1.complType() != Normal)
     return c1;
   
-  for (SourceElementsNode *n = elements.get(); n; n = n->elements.get()) {
-    Completion c2 = n->element->execute(exec);
+  for (SourceElementsNode *n = next.get(); n; n = n->next.get()) {
+    Completion c2 = n->node->execute(exec);
     if (c2.complType() != Normal)
       return c2;
     // The spec says to return c2 here, but it seems that mozilla returns c1 if
@@ -2344,14 +2346,14 @@ Completion SourceElementsNode::execute(ExecState *exec)
 // ECMA 14
 void SourceElementsNode::processFuncDecl(ExecState *exec)
 {
-  for (SourceElementsNode *n = this; n; n = n->elements.get())
-    n->element->processFuncDecl(exec);
+  for (SourceElementsNode *n = this; n; n = n->next.get())
+    n->node->processFuncDecl(exec);
 }
 
 void SourceElementsNode::processVarDecls(ExecState *exec)
 {
-  for (SourceElementsNode *n = this; n; n = n->elements.get())
-    n->element->processVarDecls(exec);
+  for (SourceElementsNode *n = this; n; n = n->next.get())
+    n->node->processVarDecls(exec);
 }
 
 ProgramNode::ProgramNode(SourceElementsNode *s) : FunctionBodyNode(s)
index a4fd2e27c29b76ba5663a3f7269e50a943fb57ed..8588e75745f3e1192b06f471f3966d8acd2df4a0 100644 (file)
@@ -26,6 +26,7 @@
 #define _NODES_H_
 
 #include <kxmlcore/RefPtr.h>
+#include <kxmlcore/ListRefPtr.h>
 
 #include "internal.h"
 
@@ -219,14 +220,15 @@ namespace KJS {
   class ElementNode : public Node {
   public:
     // list pointer is tail of a circular list, cracked in the ArrayNode ctor
-    ElementNode(int e, Node *n) : list(this), elision(e), node(n) { }
+    ElementNode(int e, Node *n) : next(this), elision(e), node(n) { }
     ElementNode(ElementNode *l, int e, Node *n)
-      : list(l->list), elision(e), node(n) { l->list = this; }
+      : next(l->next), elision(e), node(n) { l->next = this; }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<ElementNode> releaseNext() { return next.release(); }
   private:
     friend class ArrayNode;
-    RefPtr<ElementNode> list;
+    ListRefPtr<ElementNode> next;
     int elision;
     RefPtr<Node> node;
   };
@@ -235,9 +237,9 @@ namespace KJS {
   public:
     ArrayNode(int e) : element(0), elision(e), opt(true) { }
     ArrayNode(ElementNode *ele)
-      : element(ele->list), elision(0), opt(false) { ele->list = 0; }
+      : element(ele->next), elision(0), opt(false) { ele->next = 0; }
     ArrayNode(int eli, ElementNode *ele)
-      : element(ele->list), elision(eli), opt(true) { ele->list = 0; }
+      : element(ele->next), elision(eli), opt(true) { ele->next = 0; }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
@@ -274,22 +276,23 @@ namespace KJS {
   class PropertyListNode : public Node {
   public:
     // list pointer is tail of a circular list, cracked in the ObjectLiteralNode ctor
-    PropertyListNode(PropertyNode *n)\v
-      : node(n), list(this) { }
+    PropertyListNode(PropertyNode *n)
+      : node(n), next(this) { }
     PropertyListNode(PropertyNode *n, PropertyListNode *l)
-      : node(n), list(l->list) { l->list = this; }
+      : node(n), next(l->next) { l->next = this; }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<PropertyListNode> releaseNext() { return next.release(); }
   private:
     friend class ObjectLiteralNode;
     RefPtr<PropertyNode> node;
-    RefPtr<PropertyListNode> list;
+    ListRefPtr<PropertyListNode> next;
   };
 
   class ObjectLiteralNode : public Node {
   public:
     ObjectLiteralNode() : list(0) { }
-    ObjectLiteralNode(PropertyListNode *l) : list(l->list) { l->list = 0; }
+    ObjectLiteralNode(PropertyListNode *l) : list(l->next) { l->next = 0; }
     JSValue *evaluate(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
@@ -331,15 +334,16 @@ namespace KJS {
   class ArgumentListNode : public Node {
   public:
     // list pointer is tail of a circular list, cracked in the ArgumentsNode ctor
-    ArgumentListNode(Node *e) : list(this), expr(e) { }
+    ArgumentListNode(Node *e) : next(this), expr(e) { }
     ArgumentListNode(ArgumentListNode *l, Node *e)
-      : list(l->list), expr(e) { l->list = this; }
+      : next(l->next), expr(e) { l->next = this; }
     JSValue *evaluate(ExecState *exec);
     List evaluateList(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<ArgumentListNode> releaseNext() { return next.release(); }
   private:
     friend class ArgumentsNode;
-    RefPtr<ArgumentListNode> list;
+    ListRefPtr<ArgumentListNode> next;
     RefPtr<Node> expr;
   };
 
@@ -347,7 +351,7 @@ namespace KJS {
   public:
     ArgumentsNode() : list(0) { }
     ArgumentsNode(ArgumentListNode *l)
-      : list(l->list) { l->list = 0; }
+      : list(l->next) { l->next = 0; }
     JSValue *evaluate(ExecState *exec);
     List evaluateList(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
@@ -741,10 +745,11 @@ namespace KJS {
     virtual Completion execute(ExecState *exec);
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<StatListNode> releaseNext() { return next.release(); }
   private:
     friend class CaseClauseNode;
     RefPtr<StatementNode> statement;
-    RefPtr<StatListNode> list;
+    ListRefPtr<StatListNode> next;
   };
 
   class AssignExprNode : public Node {
@@ -772,27 +777,28 @@ namespace KJS {
   class VarDeclListNode : public Node {
   public:
     // list pointer is tail of a circular list, cracked in the ForNode/VarStatementNode ctor
-    VarDeclListNode(VarDeclNode *v) : list(this), var(v) {}
+    VarDeclListNode(VarDeclNode *v) : next(this), var(v) {}
     VarDeclListNode(VarDeclListNode *l, VarDeclNode *v)
-      : list(l->list), var(v) { l->list = this; }
+      : next(l->next), var(v) { l->next = this; }
     JSValue *evaluate(ExecState *exec);
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<VarDeclListNode> releaseNext() { return next.release(); }
   private:
     friend class ForNode;
     friend class VarStatementNode;
-    RefPtr<VarDeclListNode> list;
+    ListRefPtr<VarDeclListNode> next;
     RefPtr<VarDeclNode> var;
   };
 
   class VarStatementNode : public StatementNode {
   public:
-    VarStatementNode(VarDeclListNode *l) : list(l->list) { l->list = 0; }
+    VarStatementNode(VarDeclListNode *l) : next(l->next) { l->next = 0; }
     virtual Completion execute(ExecState *exec);
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
-    RefPtr<VarDeclListNode> list;
+    RefPtr<VarDeclListNode> next;
   };
 
   class BlockNode : public StatementNode {
@@ -861,7 +867,7 @@ namespace KJS {
     ForNode(Node *e1, Node *e2, Node *e3, StatementNode *s) :
       expr1(e1), expr2(e2), expr3(e3), statement(s) {}
     ForNode(VarDeclListNode *e1, Node *e2, Node *e3, StatementNode *s) :
-      expr1(e1->list), expr2(e2), expr3(e3), statement(s) { e1->list = 0; }
+      expr1(e1->next), expr2(e2), expr3(e3), statement(s) { e1->next = 0; }
     virtual Completion execute(ExecState *exec);
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
@@ -930,33 +936,34 @@ namespace KJS {
 
   class CaseClauseNode : public Node {
   public:
-    CaseClauseNode(Node *e) : expr(e), list(0) { }
+    CaseClauseNode(Node *e) : expr(e), next(0) { }
     CaseClauseNode(Node *e, StatListNode *l)
-      : expr(e), list(l->list) { l->list = 0; }
+      : expr(e), next(l->next) { l->next = 0; }
     JSValue *evaluate(ExecState *exec);
     Completion evalStatements(ExecState *exec);
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
   private:
     RefPtr<Node> expr;
-    RefPtr<StatListNode> list;
+    RefPtr<StatListNode> next;
   };
 
   class ClauseListNode : public Node {
   public:
     // list pointer is tail of a circular list, cracked in the CaseBlockNode ctor
-    ClauseListNode(CaseClauseNode *c) : cl(c), nx(this) { }
+    ClauseListNode(CaseClauseNode *c) : clause(c), next(this) { }
     ClauseListNode(ClauseListNode *n, CaseClauseNode *c)
-      : cl(c), nx(n->nx) { n->nx = this; }
+      : clause(c), next(n->next) { n->next = this; }
     JSValue *evaluate(ExecState *exec);
-    CaseClauseNode *clause() const { return cl.get(); }
-    ClauseListNode *next() const { return nx.get(); }
+    CaseClauseNode *getClause() const { return clause.get(); }
+    ClauseListNode *getNext() const { return next.get(); }
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<ClauseListNode> releaseNext() { return next.release(); }
   private:
     friend class CaseBlockNode;
-    RefPtr<CaseClauseNode> cl;
-    RefPtr<ClauseListNode> nx;
+    RefPtr<CaseClauseNode> clause;
+    ListRefPtr<ClauseListNode> next;
   };
 
   class CaseBlockNode : public Node {
@@ -1021,17 +1028,18 @@ namespace KJS {
   public:
     // list pointer is tail of a circular list, cracked in the FuncDeclNode/FuncExprNode ctor
     ParameterNode(const Identifier &i) : id(i), next(this) { }
-    ParameterNode(ParameterNode *list, const Identifier &i)
-      : id(i), next(list->next) { list->next = this; }
+    ParameterNode(ParameterNode *next, const Identifier &i)
+      : id(i), next(next->next) { next->next = this; }
     JSValue *evaluate(ExecState *exec);
     Identifier ident() { return id; }
     ParameterNode *nextParam() { return next.get(); }
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<ParameterNode> releaseNext() { return next.release(); }
   private:
     friend class FuncDeclNode;
     friend class FuncExprNode;
     Identifier id;
-    RefPtr<ParameterNode> next;
+    ListRefPtr<ParameterNode> next;
   };
 
   // inherited by ProgramNode
@@ -1073,18 +1081,20 @@ namespace KJS {
   // A linked list of source element nodes
   class SourceElementsNode : public StatementNode {
   public:
+      static int count;
     // list pointer is tail of a circular list, cracked in the BlockNode (or subclass) ctor
     SourceElementsNode(StatementNode *s1);
     SourceElementsNode(SourceElementsNode *s1, StatementNode *s2);
-
+    
     Completion execute(ExecState *exec);
     void processFuncDecl(ExecState *exec);
     virtual void processVarDecls(ExecState *exec);
     virtual void streamTo(SourceStream &s) const;
+    PassRefPtr<SourceElementsNode> releaseNext() { return next.release(); }
   private:
     friend class BlockNode;
-    RefPtr<StatementNode> element; // 'this' element
-    RefPtr<SourceElementsNode> elements; // pointer to next
+    RefPtr<StatementNode> node;
+    ListRefPtr<SourceElementsNode> next;
   };
 
   class ProgramNode : public FunctionBodyNode {
index 1bd92c36e1f163f059c028b485e4bfb85e4cf384..1808a36ea9b6b63f88aa39fe51c8ece238ab17eb 100644 (file)
@@ -132,7 +132,7 @@ void GroupNode::streamTo(SourceStream &s) const
 
 void ElementNode::streamTo(SourceStream &s) const
 {
-  for (const ElementNode *n = this; n; n = n->list.get()) {
+  for (const ElementNode *n = this; n; n = n->next.get()) {
     for (int i = 0; i < n->elision; i++)
       s << ",";
     s << n->node;
@@ -159,7 +159,7 @@ void PropertyListNode::streamTo(SourceStream &s) const
 {
   s << node;
   
-  for (const PropertyListNode *n = list.get(); n; n = n->list.get())
+  for (const PropertyListNode *n = next.get(); n; n = n->next.get())
     s << ", " << n->node;
 }
 
@@ -204,7 +204,7 @@ void DotAccessorNode::streamTo(SourceStream &s) const
 void ArgumentListNode::streamTo(SourceStream &s) const
 {
   s << expr;
-  for (ArgumentListNode *n = list.get(); n; n = n->list.get())
+  for (ArgumentListNode *n = next.get(); n; n = n->next.get())
     s << ", " << n->expr;
 }
 
@@ -525,7 +525,7 @@ void CommaNode::streamTo(SourceStream &s) const
 
 void StatListNode::streamTo(SourceStream &s) const
 {
-  for (const StatListNode *n = this; n; n = n->list.get())
+  for (const StatListNode *n = this; n; n = n->next.get())
     s << n->statement;
 }
 
@@ -542,13 +542,13 @@ void VarDeclNode::streamTo(SourceStream &s) const
 void VarDeclListNode::streamTo(SourceStream &s) const
 {
   s << var;
-  for (VarDeclListNode *n = list.get(); n; n = n->list.get())
+  for (VarDeclListNode *n = next.get(); n; n = n->next.get())
     s << ", " << n->var;
 }
 
 void VarStatementNode::streamTo(SourceStream &s) const
 {
-  s << SourceStream::Endl << "var " << list << ";";
+  s << SourceStream::Endl << "var " << next << ";";
 }
 
 void BlockNode::streamTo(SourceStream &s) const
@@ -650,25 +650,25 @@ void CaseClauseNode::streamTo(SourceStream &s) const
   else
     s << "default";
   s << ":" << SourceStream::Indent;
-  if (list)
-    s << list;
+  if (next)
+    s << next;
   s << SourceStream::Unindent;
 }
 
 void ClauseListNode::streamTo(SourceStream &s) const
 {
-  for (const ClauseListNode *n = this; n; n = n->next())
-    s << n->clause();
+  for (const ClauseListNode *n = this; n; n = n->getNext())
+    s << n->getClause();
 }
 
 void CaseBlockNode::streamTo(SourceStream &s) const
 {
-  for (const ClauseListNode *n = list1.get(); n; n = n->next())
-    s << n->clause();
+  for (const ClauseListNode *n = list1.get(); n; n = n->getNext())
+    s << n->getClause();
   if (def)
     s << def;
-  for (const ClauseListNode *n = list2.get(); n; n = n->next())
-    s << n->clause();
+  for (const ClauseListNode *n = list2.get(); n; n = n->getNext())
+    s << n->getClause();
 }
 
 void SwitchNode::streamTo(SourceStream &s) const
@@ -717,6 +717,6 @@ void FuncExprNode::streamTo(SourceStream &s) const
 
 void SourceElementsNode::streamTo(SourceStream &s) const
 {
-  for (const SourceElementsNode *n = this; n; n = n->elements.get())
-    s << n->element;
+  for (const SourceElementsNode *n = this; n; n = n->next.get())
+    s << n->node;
 }
diff --git a/JavaScriptCore/kxmlcore/ListRefPtr.h b/JavaScriptCore/kxmlcore/ListRefPtr.h
new file mode 100644 (file)
index 0000000..3952c50
--- /dev/null
@@ -0,0 +1,59 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ *  This file is part of the KDE libraries
+ *  Copyright (C) 2005 Apple Computer, Inc.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KXMLCORE_LIST_REF_PTR_H
+#define KXMLCORE_LIST_REF_PTR_H
+
+#include <kxmlcore/RefPtr.h>
+#include <algorithm>
+
+namespace KXMLCore {
+
+    // Specialized version of RefPtr desgined for use in singly-linked lists. 
+    // Derefs the list iteratively to avoid recursive derefing that can overflow the stack.
+    template <typename T> class ListRefPtr : public RefPtr<T>
+    {
+    public:
+        ListRefPtr() : RefPtr<T>() {}
+        ListRefPtr(T *ptr) : RefPtr<T>(ptr) {}
+        ListRefPtr(const RefPtr<T>& o) : RefPtr<T>(o) {}
+        // see comment in PassRefPtr.h for why this takes const reference
+        template <typename U> ListRefPtr(const PassRefPtr<U>& o) : RefPtr<T>(o) {}
+
+        ~ListRefPtr() {
+            RefPtr<T> reaper = this->release();
+            while (reaper && reaper->refcount() == 1)
+                reaper = reaper->releaseNext(); // implicitly protects reaper->next, then derefs reaper
+        }
+        
+        ListRefPtr& operator=(T *optr) { RefPtr<T>::operator=(optr); return *this; }
+        ListRefPtr& operator=(const RefPtr<T>& o) { RefPtr<T>::operator=(o); return *this; }
+        ListRefPtr& operator=(const PassRefPtr<T>& o) { RefPtr<T>::operator=(o); return *this; }
+        template <typename U> ListRefPtr& operator=(const RefPtr<U>& o) { RefPtr<T>::operator=(o); return *this; }
+        template <typename U> ListRefPtr& operator=(const PassRefPtr<U>& o) { RefPtr<T>::operator=(o); return *this; }
+    };
+
+} // namespace KXMLCore
+
+using KXMLCore::ListRefPtr;
+
+#endif // KXMLCORE_LIST_REF_PTR_H
index c5ecd9ef8d7f55d6d851fc18a42895ab8c570e61..c259fb424da5694d0d2feb08f5435e0921371173 100644 (file)
@@ -44,6 +44,8 @@ namespace KXMLCore {
         
         T *get() const { return m_ptr; }
         
+        PassRefPtr<T> release() { PassRefPtr<T> tmp = adoptRef(m_ptr); m_ptr = 0; return tmp; }
+
         T& operator*() const { return *m_ptr; }
         T *operator->() const { return m_ptr; }
         
index 0ca9d742dffb469f911dafcd5fa91a4279e02e12..c804d88873d5e76f20610a6d3b7876d1f8e64802 100644 (file)
@@ -38,7 +38,7 @@
 * SUMMARY: Testing script with at least 64K of different string literals
 * See http://bugzilla.mozilla.org/show_bug.cgi?id=159334
 *
-* Testing that script engine can handle scripts with at least 64K of different
+* Testing that script engine can handle scripts with at least 128K of different
 * string literals. The following will evaluate, via eval(), a script like this:
 *
 *     f('0')
 *     ...
 *     f('N - 1')
 *
-* where N is 0xFFFE
+* where N is 0x20000
 *
 */
 //-----------------------------------------------------------------------------
 var UBound = 0;
 var bug = 159334;
-var summary = 'Testing script with at least 64K of different string literals';
+var summary = 'Testing script with at least 128K of different string literals';
 var status = '';
 var statusitems = [];
 var actual = '';
@@ -61,7 +61,7 @@ var expect= '';
 var expectedvalues = [];
 
 
-var N = 0xFFFE;
+var N = 0x20000;
 
 // Create big string for eval recursively to avoid N*N behavior
 // on string concatenation