OSDN Git Service

2004-07-08 Frank Ch. Eigler <fche@redhat.com>
authorfche <fche@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Jul 2004 19:11:44 +0000 (19:11 +0000)
committerfche <fche@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Jul 2004 19:11:44 +0000 (19:11 +0000)
ANSI C conversion, libmudflap specialization, recursion limiting.
* splay-tree.h (splay_tree_{de,}allocate_fn): Remove allocation_data
argument and indirection function pointers, update callers.
(splay_tree_s): Add statistics and recursion control fields
num_keys, max_depth, depth, rebalance_p.
* splay-tree.c (splay_tree_splay_helper): Track recursion depth.
Back out of search if it exceeds limit.
(splay_tree_splay): Manage recursion limiting with rebalancing as
needed.
(splay_tree_new): More initialization.
(splay_tree_rebalance): New function.
(splay_tree_foreach): Rewrite using nonrecursive logic.
(splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate):
Remove.  Point indirect calls to mf-runtime.c's routines.
(splay_tree_compare_ints, splay_tree_compare_pointers): Remove unused
functions.
(splay_tree_delete, splay_tree_delete_helper): Ditto.
* testsuite/heap-scalestress.c: New test based on one from
Eyal Lebedinsky <eyal@eyal.emu.id.au>:

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@84303 138bc75d-0d04-0410-961f-82ee72b054a4

libmudflap/ChangeLog
libmudflap/splay-tree.c
libmudflap/splay-tree.h
libmudflap/testsuite/libmudflap.c/heap-scalestress.c [new file with mode: 0644]

index 0eef621..04ce472 100644 (file)
@@ -1,3 +1,25 @@
+2004-07-08  Frank Ch. Eigler  <fche@redhat.com>
+
+       ANSI C conversion, libmudflap specialization, recursion limiting.
+       * splay-tree.h (splay_tree_{de,}allocate_fn): Remove allocation_data
+       argument and indirection function pointers, update callers.
+       (splay_tree_s): Add statistics and recursion control fields
+       num_keys, max_depth, depth, rebalance_p.
+       * splay-tree.c (splay_tree_splay_helper): Track recursion depth.
+       Back out of search if it exceeds limit.
+       (splay_tree_splay): Manage recursion limiting with rebalancing as
+       needed.
+       (splay_tree_new): More initialization.
+       (splay_tree_rebalance): New function.
+       (splay_tree_foreach): Rewrite using nonrecursive logic.
+       (splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate):
+       Remove.  Point indirect calls to mf-runtime.c's routines.
+       (splay_tree_compare_ints, splay_tree_compare_pointers): Remove unused
+       functions.
+       (splay_tree_delete, splay_tree_delete_helper): Ditto.
+       * testsuite/heap-scalestress.c: New test based on one from
+       Eyal Lebedinsky <eyal@eyal.emu.id.au>:
+
 2004-07-05  Matthias Klose  <doko@debian.org>
 
        * libtool-version: New.
index 037baee..229ef94 100644 (file)
@@ -38,20 +38,16 @@ Boston, MA 02111-1307, USA.  */
 #include <stdio.h>
 #include "splay-tree.h"
 
-static void splay_tree_delete_helper    PARAMS((splay_tree, 
-                                               splay_tree_node));
-static void splay_tree_splay            PARAMS((splay_tree,
-                                               splay_tree_key));
-static splay_tree_node splay_tree_splay_helper     
-                                        PARAMS((splay_tree,
-                                               splay_tree_key,
-                                               splay_tree_node*,
-                                               splay_tree_node*,
-                                               splay_tree_node*));
-static int splay_tree_foreach_helper    PARAMS((splay_tree,
-                                               splay_tree_node,
-                                               splay_tree_foreach_fn,
-                                               void*));
+
+static void splay_tree_delete_helper (splay_tree, splay_tree_node);
+static void splay_tree_splay (splay_tree, splay_tree_key);
+static splay_tree_node splay_tree_splay_helper (splay_tree,
+                                                splay_tree_key,
+                                                splay_tree_node *,
+                                                splay_tree_node *,
+                                                splay_tree_node *);
+static void *splay_tree_xmalloc (size_t size);
+static void splay_tree_free (void *object);
 
 
 
@@ -63,42 +59,25 @@ compare_uintptr_t (splay_tree_key k1, splay_tree_key k2)
     return -1;
   else if ((uintptr_t) k1 > (uintptr_t) k2)
     return 1;
-  else 
+  else
     return 0;
 }
 
 
-
-/* Deallocate NODE (a member of SP), and all its sub-trees.  */
-
-static void 
-splay_tree_delete_helper (sp, node)
-     splay_tree sp;
-     splay_tree_node node;
-{
-  if (!node)
-    return;
-
-  splay_tree_delete_helper (sp, node->left);
-  splay_tree_delete_helper (sp, node->right);
-  (*sp->deallocate) ((char*) node, sp->allocate_data);
-}
-
 /* Help splay SP around KEY.  PARENT and GRANDPARENT are the parent
    and grandparent, respectively, of NODE.  */
 
 static splay_tree_node
-splay_tree_splay_helper (sp, key, node, parent, grandparent)
-     splay_tree sp;
-     splay_tree_key key;
-     splay_tree_node *node;
-     splay_tree_node *parent;
-     splay_tree_node *grandparent;
+splay_tree_splay_helper (splay_tree sp,
+                         splay_tree_key key,
+                         splay_tree_node * node,
+                         splay_tree_node * parent,
+                         splay_tree_node * grandparent)
 {
   splay_tree_node *next;
   splay_tree_node n;
   int comparison;
-  
+
   n = *node;
 
   if (!n)
@@ -112,19 +91,29 @@ splay_tree_splay_helper (sp, key, node, parent, grandparent)
   else if (comparison < 0)
     /* The target is to the left.  */
     next = &n->left;
-  else 
+  else
     /* The target is to the right.  */
     next = &n->right;
 
   if (next)
     {
+      /* Check whether our recursion depth is too high.  Abort this search,
+         and signal that a rebalance is required to continue.  */
+      if (sp->depth > sp->max_depth)
+        {
+          sp->rebalance_p = 1;
+          return n;
+         }
+
       /* Continue down the tree.  */
+      sp->depth ++;
       n = splay_tree_splay_helper (sp, key, next, node, parent);
+      sp->depth --;
 
       /* The recursive call will change the place to which NODE
-        points.  */
-      if (*node != n)
-       return n;
+         points.  */
+      if (*node != n || sp->rebalance_p)
+        return n;
     }
 
   if (!parent)
@@ -132,19 +121,19 @@ splay_tree_splay_helper (sp, key, node, parent, grandparent)
     return n;
 
   /* First, handle the case where there is no grandparent (i.e.,
-     *PARENT is the root of the tree.)  */
-  if (!grandparent) 
+   *PARENT is the root of the tree.)  */
+  if (!grandparent)
     {
       if (n == (*parent)->left)
-       {
-         *node = n->right;
-         n->right = *parent;
-       }
+        {
+          *node = n->right;
+          n->right = *parent;
+        }
       else
-       {
-         *node = n->left;
-         n->left = *parent;
-       }
+        {
+          *node = n->left;
+          n->left = *parent;
+        }
       *parent = n;
       return n;
     }
@@ -160,9 +149,9 @@ splay_tree_splay_helper (sp, key, node, parent, grandparent)
       p->left = n->right;
       n->right = p;
       *grandparent = n;
-      return n; 
+      return n;
     }
-  else if  (n == (*parent)->right && *parent == (*grandparent)->right)
+  else if (n == (*parent)->right && *parent == (*grandparent)->right)
     {
       splay_tree_node p = *parent;
 
@@ -176,7 +165,7 @@ splay_tree_splay_helper (sp, key, node, parent, grandparent)
 
   /* Finally, deal with the case where N is a left child, but *PARENT
      is a right child, or vice versa.  */
-  if (n == (*parent)->left) 
+  if (n == (*parent)->left)
     {
       (*parent)->left = n->right;
       n->right = *parent;
@@ -184,7 +173,7 @@ splay_tree_splay_helper (sp, key, node, parent, grandparent)
       n->left = *grandparent;
       *grandparent = n;
       return n;
-    } 
+    }
   else
     {
       (*parent)->right = n->left;
@@ -196,117 +185,128 @@ splay_tree_splay_helper (sp, key, node, parent, grandparent)
     }
 }
 
-/* Splay SP around KEY.  */
 
-static void
-splay_tree_splay (sp, key)
-     splay_tree sp;
-     splay_tree_key key;
+
+static int
+splay_tree_rebalance_helper1 (splay_tree_node n, void *array_ptr)
 {
-  if (sp->root == 0)
-    return;
+  splay_tree_node **p = array_ptr;
+  *(*p) = n;
+  (*p)++;
+  return 0;
+}
 
-  /* If we just splayed the tree with the same key, do nothing.  */
-  if (sp->last_splayed_key_p &&
-      compare_uintptr_t (sp->last_splayed_key, key) == 0)
-    return;
 
-  splay_tree_splay_helper (sp, key, &sp->root, 
-                          /*grandparent=*/0, /*parent=*/0); 
+static splay_tree_node
+splay_tree_rebalance_helper2 (splay_tree_node * array, unsigned low,
+                              unsigned high)
+{
+  unsigned middle = low + (high - low) / 2;
+  splay_tree_node n = array[middle];
 
-  /* Cache this splay key. */
-  sp->last_splayed_key = key;
-  sp->last_splayed_key_p = 1;
+  /* Note that since we're producing a balanced binary tree, it is not a problem
+     that this function is recursive.  */
+  if (low + 1 <= middle)
+    n->left = splay_tree_rebalance_helper2 (array, low, middle - 1);
+  else
+    n->left = NULL;
+
+  if (middle + 1 <= high)
+    n->right = splay_tree_rebalance_helper2 (array, middle + 1, high);
+  else
+    n->right = NULL;
+
+  return n;
 }
 
-/* Call FN, passing it the DATA, for every node below NODE, all of
-   which are from SP, following an in-order traversal.  If FN every
-   returns a non-zero value, the iteration ceases immediately, and the
-   value is returned.  Otherwise, this function returns 0.  */
 
-static int
-splay_tree_foreach_helper (sp, node, fn, data)
-     splay_tree sp;
-     splay_tree_node node;
-     splay_tree_foreach_fn fn;
-     void* data;
+/* Rebalance the entire tree.  Do this by copying all the node
+   pointers into an array, then cleverly re-linking them.  */
+void
+splay_tree_rebalance (splay_tree sp)
 {
-  int val;
-
-  if (!node)
-    return 0;
+  splay_tree_node *all_nodes, *all_nodes_1;
 
-  val = splay_tree_foreach_helper (sp, node->left, fn, data);
-  if (val)
-    return val;
+  if (sp->num_keys <= 2)
+    return;
 
-  val = (*fn)(node, data);
-  if (val)
-    return val;
+  all_nodes = splay_tree_xmalloc (sizeof (splay_tree_node) * sp->num_keys);
 
-  return splay_tree_foreach_helper (sp, node->right, fn, data);
-}
+  /* Traverse all nodes to copy their addresses into this array.  */
+  all_nodes_1 = all_nodes;
+  splay_tree_foreach (sp, splay_tree_rebalance_helper1,
+                      (void *) &all_nodes_1);
 
+  /* Relink all the nodes.  */
+  sp->root = splay_tree_rebalance_helper2 (all_nodes, 0, sp->num_keys - 1);
 
-/* An allocator and deallocator based on xmalloc.  */
-static void *
-splay_tree_xmalloc_allocate (size, data)
-     int size;
-     void *data ATTRIBUTE_UNUSED;
-{
-  return (void *) xmalloc (size);
+  splay_tree_free (all_nodes);
 }
 
+
+/* Splay SP around KEY.  */
 static void
-splay_tree_xmalloc_deallocate (object, data)
-     void *object;
-     void *data ATTRIBUTE_UNUSED;
+splay_tree_splay (splay_tree sp, splay_tree_key key)
 {
-  free (object);
+  if (sp->root == 0)
+    return;
+
+  /* If we just splayed the tree with the same key, do nothing.  */
+  if (sp->last_splayed_key_p &&
+      compare_uintptr_t (sp->last_splayed_key, key) == 0)
+    return;
+
+  /* Compute a maximum recursion depth for a splay tree with NUM nodes.
+     The idea is to limit excessive stack usage if we're facing
+     degenerate access patterns.  Unfortunately such patterns can occur
+     e.g. during static initialization, where many static objects might
+     be registered in increasing address sequence, or during a case where
+     large tree-like heap data structures are allocated quickly. 
+
+     On x86, this corresponds to roughly 200K of stack usage. 
+     XXX: For libmudflapth, this could be a function of __mf_opts.thread_stack.  */
+  sp->max_depth = 2500;
+  sp->rebalance_p = sp->depth = 0;
+
+  splay_tree_splay_helper (sp, key, &sp->root, NULL, NULL);
+  if (sp->rebalance_p)
+    {
+      splay_tree_rebalance (sp);
+
+      sp->rebalance_p = sp->depth = 0;
+      splay_tree_splay_helper (sp, key, &sp->root, NULL, NULL);
+
+      if (sp->rebalance_p)
+        abort ();
+    }
+
+
+  /* Cache this splay key. */
+  sp->last_splayed_key = key;
+  sp->last_splayed_key_p = 1;
 }
 
 
-/* Allocate a new splay tree, using COMPARE_FN to compare nodes,
-   DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
-   values.  Use xmalloc to allocate the splay tree structure, and any
-   nodes added.  */
 
-splay_tree 
+/* Allocate a new splay tree.  */
+splay_tree
 splay_tree_new ()
 {
-  splay_tree_allocate_fn allocate_fn = splay_tree_xmalloc_allocate;
-  splay_tree_deallocate_fn deallocate_fn = splay_tree_xmalloc_deallocate;
-  void *allocate_data = NULL;
-  splay_tree sp = (splay_tree) (*allocate_fn) (sizeof (struct splay_tree_s),
-                                               allocate_data);
-  sp->root = 0;
-  sp->allocate = allocate_fn;
-  sp->deallocate = deallocate_fn;
-  sp->allocate_data = allocate_data;
+  splay_tree sp = splay_tree_xmalloc (sizeof (struct splay_tree_s));
+  sp->root = NULL;
   sp->last_splayed_key_p = 0;
+  sp->num_keys = 0;
 
   return sp;
 }
 
-/* Deallocate SP.  */
 
-void 
-splay_tree_delete (sp)
-     splay_tree sp;
-{
-  splay_tree_delete_helper (sp, sp->root);
-  (*sp->deallocate) ((char*) sp, sp->allocate_data);
-}
 
 /* Insert a new node (associating KEY with DATA) into SP.  If a
    previous node with the indicated KEY exists, its data is replaced
    with the new value.  Returns the new node.  */
-
 splay_tree_node
-splay_tree_insert (sp, key, value)
-     splay_tree sp;
-     splay_tree_key key;
-     splay_tree_value value;
+splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
 {
   int comparison = 0;
 
@@ -318,34 +318,32 @@ splay_tree_insert (sp, key, value)
   if (sp->root && comparison == 0)
     {
       /* If the root of the tree already has the indicated KEY, just
-        replace the value with VALUE.  */
+         replace the value with VALUE.  */
       sp->root->value = value;
-    } 
-  else 
+    }
+  else
     {
       /* Create a new node, and insert it at the root.  */
       splay_tree_node node;
-      
-      node = ((splay_tree_node)
-              (*sp->allocate) (sizeof (struct splay_tree_node_s),
-                               sp->allocate_data));
+
+      node = splay_tree_xmalloc (sizeof (struct splay_tree_node_s));
       node->key = key;
       node->value = value;
-      
+      sp->num_keys++;
       if (!sp->root)
-       node->left = node->right = 0;
+        node->left = node->right = 0;
       else if (comparison < 0)
-       {
-         node->left = sp->root;
-         node->right = node->left->right;
-         node->left->right = 0;
-       }
+        {
+          node->left = sp->root;
+          node->right = node->left->right;
+          node->left->right = 0;
+        }
       else
-       {
-         node->right = sp->root;
-         node->left = node->right->left;
-         node->right->left = 0;
-       }
+        {
+          node->right = sp->root;
+          node->left = node->right->left;
+          node->right->left = 0;
+        }
 
       sp->root = node;
       sp->last_splayed_key_p = 0;
@@ -357,40 +355,34 @@ splay_tree_insert (sp, key, value)
 /* Remove KEY from SP.  It is not an error if it did not exist.  */
 
 void
-splay_tree_remove (sp, key)
-     splay_tree sp;
-     splay_tree_key key;
+splay_tree_remove (splay_tree sp, splay_tree_key key)
 {
   splay_tree_splay (sp, key);
   sp->last_splayed_key_p = 0;
-
   if (sp->root && compare_uintptr_t (sp->root->key, key) == 0)
     {
       splay_tree_node left, right;
-
       left = sp->root->left;
       right = sp->root->right;
-
       /* Delete the root node itself.  */
-      (*sp->deallocate) (sp->root, sp->allocate_data);
-
+      splay_tree_free (sp->root);
+      sp->num_keys--;
       /* One of the children is now the root.  Doesn't matter much
-        which, so long as we preserve the properties of the tree.  */
+         which, so long as we preserve the properties of the tree.  */
       if (left)
-       {
-         sp->root = left;
-
-         /* If there was a right child as well, hang it off the 
-            right-most leaf of the left child.  */
-         if (right)
-           {
-             while (left->right)
-               left = left->right;
-             left->right = right;
-           }
-       }
+        {
+          sp->root = left;
+          /* If there was a right child as well, hang it off the 
+             right-most leaf of the left child.  */
+          if (right)
+            {
+              while (left->right)
+                left = left->right;
+              left->right = right;
+            }
+        }
       else
-       sp->root = right;
+        sp->root = right;
     }
 }
 
@@ -398,12 +390,9 @@ splay_tree_remove (sp, key)
    otherwise.  */
 
 splay_tree_node
-splay_tree_lookup (sp, key)
-     splay_tree sp;
-     splay_tree_key key;
+splay_tree_lookup (splay_tree sp, splay_tree_key key)
 {
   splay_tree_splay (sp, key);
-
   if (sp->root && compare_uintptr_t (sp->root->key, key) == 0)
     return sp->root;
   else
@@ -413,34 +402,26 @@ splay_tree_lookup (sp, key)
 /* Return the node in SP with the greatest key.  */
 
 splay_tree_node
-splay_tree_max (sp)
-     splay_tree sp;
+splay_tree_max (splay_tree sp)
 {
   splay_tree_node n = sp->root;
-
   if (!n)
     return NULL;
-
   while (n->right)
     n = n->right;
-
   return n;
 }
 
 /* Return the node in SP with the smallest key.  */
 
 splay_tree_node
-splay_tree_min (sp)
-     splay_tree sp;
+splay_tree_min (splay_tree sp)
 {
   splay_tree_node n = sp->root;
-
   if (!n)
     return NULL;
-
   while (n->left)
     n = n->left;
-
   return n;
 }
 
@@ -448,32 +429,25 @@ splay_tree_min (sp)
    predecessor.  KEY need not be present in the tree.  */
 
 splay_tree_node
-splay_tree_predecessor (sp, key)
-     splay_tree sp;
-     splay_tree_key key;
+splay_tree_predecessor (splay_tree sp, splay_tree_key key)
 {
   int comparison;
   splay_tree_node node;
-
   /* If the tree is empty, there is certainly no predecessor.  */
   if (!sp->root)
     return NULL;
-
   /* Splay the tree around KEY.  That will leave either the KEY
      itself, its predecessor, or its successor at the root.  */
   splay_tree_splay (sp, key);
   comparison = compare_uintptr_t (sp->root->key, key);
-
   /* If the predecessor is at the root, just return it.  */
   if (comparison < 0)
     return sp->root;
-
   /* Otherwise, find the rightmost element of the left subtree.  */
   node = sp->root->left;
   if (node)
     while (node->right)
       node = node->right;
-
   return node;
 }
 
@@ -481,45 +455,111 @@ splay_tree_predecessor (sp, key)
    successor.  KEY need not be present in the tree.  */
 
 splay_tree_node
-splay_tree_successor (sp, key)
-     splay_tree sp;
-     splay_tree_key key;
+splay_tree_successor (splay_tree sp, splay_tree_key key)
 {
   int comparison;
   splay_tree_node node;
-
   /* If the tree is empty, there is certainly no successor.  */
   if (!sp->root)
     return NULL;
-
   /* Splay the tree around KEY.  That will leave either the KEY
      itself, its predecessor, or its successor at the root.  */
   splay_tree_splay (sp, key);
   comparison = compare_uintptr_t (sp->root->key, key);
-
   /* If the successor is at the root, just return it.  */
   if (comparison > 0)
     return sp->root;
-
   /* Otherwise, find the leftmost element of the right subtree.  */
   node = sp->root->right;
   if (node)
     while (node->left)
       node = node->left;
-
   return node;
 }
 
 /* Call FN, passing it the DATA, for every node in SP, following an
    in-order traversal.  If FN every returns a non-zero value, the
    iteration ceases immediately, and the value is returned.
-   Otherwise, this function returns 0.  */
-
+   Otherwise, this function returns 0.
+   
+   This function simulates recursion using dynamically allocated
+   arrays, since it may be called from splay_tree_rebalance(), which
+   in turn means that the tree is already uncomfortably deep for stack
+   space limits.  */
 int
-splay_tree_foreach (sp, fn, data)
-     splay_tree sp;
-     splay_tree_foreach_fn fn;
-     void *data;
+splay_tree_foreach (splay_tree st, splay_tree_foreach_fn fn, void *data)
 {
-  return splay_tree_foreach_helper (sp, sp->root, fn, data);
+  splay_tree_node *stack1;
+  char *stack2;
+  unsigned sp;
+  int val = 0;
+  enum s { s_left, s_here, s_right, s_up };
+
+  if (st->root == NULL) /* => num_keys == 0 */
+    return 0;
+
+  stack1 = splay_tree_xmalloc (sizeof (splay_tree_node) * st->num_keys);
+  stack2 = splay_tree_xmalloc (sizeof (char) * st->num_keys);
+
+  sp = 0;
+  stack1 [sp] = st->root;
+  stack2 [sp] = s_left;
+
+  while (1)
+    {
+      splay_tree_node n;
+      enum s s;
+
+      n = stack1 [sp];
+      s = stack2 [sp];
+
+      /* Handle each of the four possible states separately.  */
+
+      /* 1: We're here to traverse the left subtree (if any).  */
+      if (s == s_left)
+        {
+          stack2 [sp] = s_here;
+          if (n->left != NULL)
+            {
+              sp ++;
+              stack1 [sp] = n->left;
+              stack2 [sp] = s_left;
+            }
+        }
+
+      /* 2: We're here to traverse this node.  */
+      else if (s == s_here)
+        {
+          stack2 [sp] = s_right;
+          val = (*fn) (n, data);
+          if (val) break;
+        }
+
+      /* 3: We're here to traverse the right subtree (if any).  */
+      else if (s == s_right)
+        {
+          stack2 [sp] = s_up;
+          if (n->right != NULL)
+            {
+              sp ++;
+              stack1 [sp] = n->right;
+              stack2 [sp] = s_left;
+            }
+        }
+
+      /* 4: We're here after both subtrees (if any) have been traversed.  */
+      else if (s == s_up)
+        {
+          /* Pop the stack.  */
+          if (sp == 0) break; /* Popping off the root note: we're finished!  */
+          sp --;
+        }
+
+      else
+        abort ();
+    }
+
+  splay_tree_free (stack1);
+  splay_tree_free (stack2);
+  return val;
 }
index 269394d..742eb4b 100644 (file)
@@ -1,7 +1,7 @@
 /* A splay-tree datatype.  
    Copyright 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
    Contributed by Mark Mitchell (mark@markmitchell.com).
-   Adapted for libmudflap from libiberty.
+   Adapted for libmudflap from libiberty by Frank Ch. Eigler <fche@redhat.com>.
 
 This file is part of GCC.
    
@@ -26,23 +26,16 @@ Boston, MA 02111-1307, USA.  */
      Algorithms.  Harper-Collins, Inc.  1991.  
 
    The major feature of splay trees is that all basic tree operations
-   are amortized O(log n) time for a tree with n nodes.  */
+   are amortized O(log n) time for a tree with n nodes.  
+
+   This version has been further modified to periodically rebalance
+   the entire tree, should degenerate access patterns result in a very
+   lopsided tree.
+*/
 
 #ifndef _SPLAY_TREE_H
 #define _SPLAY_TREE_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define PARAMS(X) X
-#define PTR  void *
-#define ATTRIBUTE_UNUSED __attribute__((__unused__))
-
-#ifndef GTY
-#define GTY(X)
-#endif
-
 /* Use typedefs for the key and data types to facilitate changing
    these types, if necessary.  These types should be sufficiently wide
    that any pointer or scalar can be cast to these types, and then
@@ -54,83 +47,50 @@ typedef void *splay_tree_value;
 typedef struct splay_tree_node_s *splay_tree_node;
 
 /* The type of a function used to iterate over the tree.  */
-typedef int (*splay_tree_foreach_fn) PARAMS((splay_tree_node, void*));
-
-/* The type of a function used to allocate memory for tree root and
-   node structures.  The first argument is the number of bytes needed;
-   the second is a data pointer the splay tree functions pass through
-   to the allocator.  This function must never return zero.  */
-typedef PTR (*splay_tree_allocate_fn) PARAMS((int, void *));
-
-/* The type of a function used to free memory allocated using the
-   corresponding splay_tree_allocate_fn.  The first argument is the
-   memory to be freed; the latter is a data pointer the splay tree
-   functions pass through to the freer.  */
-typedef void (*splay_tree_deallocate_fn) PARAMS((void *, void *));
+typedef int (*splay_tree_foreach_fn) (splay_tree_node, void *);
 
 /* The nodes in the splay tree.  */
-struct splay_tree_node_s GTY(())
+struct splay_tree_node_s
 {
-  /* The key.  */
-  splay_tree_key GTY ((use_param1)) key;
-
-  /* The value.  */
-  splay_tree_value GTY ((use_param2)) value;
-
-  /* The left and right children, respectively.  */
-  splay_tree_node GTY ((use_params)) left;
-  splay_tree_node GTY ((use_params)) right;
+  /* Data.  */
+  splay_tree_key key;
+  splay_tree_value value;
+  /* Children.  */
+  splay_tree_node left;
+  splay_tree_node right;
 };
 
 /* The splay tree itself.  */
-struct splay_tree_s GTY(())
+struct splay_tree_s
 {
   /* The root of the tree.  */
-  splay_tree_node GTY ((use_params)) root;
-
-  /* Allocate/free functions, and a data pointer to pass to them.  */
-  splay_tree_allocate_fn allocate;
-  splay_tree_deallocate_fn deallocate;
-  PTR GTY((skip)) allocate_data;
+  splay_tree_node root;
 
   /* The last key value for which the tree has been splayed, but not
      since modified.  */
-  splay_tree_key GTY ((use_param1)) last_splayed_key;
+  splay_tree_key last_splayed_key;
   int last_splayed_key_p;
+
+  /* Statistics.  */
+  unsigned num_keys;
+
+  /* Traversal recursion control flags.  */
+  unsigned max_depth;
+  unsigned depth;
+  unsigned rebalance_p;
 };
 typedef struct splay_tree_s *splay_tree;
 
-extern splay_tree splay_tree_new        PARAMS((void));
-extern void splay_tree_delete           PARAMS((splay_tree));
-extern splay_tree_node splay_tree_insert          
-                                       PARAMS((splay_tree,
-                                               splay_tree_key,
-                                               splay_tree_value));
-extern void splay_tree_remove          PARAMS((splay_tree,
-                                               splay_tree_key));
-extern splay_tree_node splay_tree_lookup   
-                                        PARAMS((splay_tree,
-                                               splay_tree_key));
-extern splay_tree_node splay_tree_predecessor
-                                        PARAMS((splay_tree,
-                                               splay_tree_key));
-extern splay_tree_node splay_tree_successor
-                                        PARAMS((splay_tree,
-                                               splay_tree_key));
-extern splay_tree_node splay_tree_max
-                                        PARAMS((splay_tree));
-extern splay_tree_node splay_tree_min
-                                        PARAMS((splay_tree));
-extern int splay_tree_foreach           PARAMS((splay_tree,
-                                               splay_tree_foreach_fn,
-                                               void*));
-extern int splay_tree_compare_ints      PARAMS((splay_tree_key,
-                                               splay_tree_key));
-extern int splay_tree_compare_pointers  PARAMS((splay_tree_key,
-                                               splay_tree_key));
-                                              
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+extern splay_tree splay_tree_new (void);
+extern splay_tree_node splay_tree_insert (splay_tree, splay_tree_key, splay_tree_value);
+extern void splay_tree_remove (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_lookup (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_predecessor (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_successor (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_max (splay_tree);
+extern splay_tree_node splay_tree_min (splay_tree);
+extern int splay_tree_foreach (splay_tree, splay_tree_foreach_fn, void *);
+extern void splay_tree_rebalance (splay_tree sp);
+
 
 #endif /* _SPLAY_TREE_H */
diff --git a/libmudflap/testsuite/libmudflap.c/heap-scalestress.c b/libmudflap/testsuite/libmudflap.c/heap-scalestress.c
new file mode 100644 (file)
index 0000000..2d51731
--- /dev/null
@@ -0,0 +1,79 @@
+/* zz30
+ *
+ * demonstrate a splay-tree depth problem
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifndef SCALE
+#define SCALE 100000
+#endif
+
+
+struct list
+{
+  struct list *next;
+};
+
+
+int
+main ()
+{
+  struct list *head = NULL;
+  struct list *tail = NULL;
+  struct list *p;
+  long n;
+  int direction;
+
+  for (direction = 0; direction < 2; direction++)
+    {
+      fprintf (stdout, "allocating\n");
+      fflush (stdout);
+
+      for (n = 0; n < SCALE; ++n)
+       {
+         p = malloc (sizeof *p);
+         if (NULL == p)
+           {
+             fprintf (stdout, "malloc failed\n");
+             break;
+           }
+         if (direction == 0)
+           {                   /* add at tail */
+             p->next = NULL;
+             if (NULL != tail)
+               tail->next = p;
+             else
+               head = p;
+             tail = p;
+           }
+         else
+           {                   /* add at head */
+             p->next = head;
+             if (NULL == tail)
+               tail = p;
+             head = p;
+           }
+       }
+
+      fprintf (stdout, "freeing\n");
+      fflush (stdout);
+
+      while (NULL != head)
+       {
+         p = head;
+         head = head->next;
+         free (p);
+       }
+
+    }
+
+  fprintf (stdout, "done\n");
+  fflush (stdout);
+
+  return (0);
+}
+
+/* { dg-output "allocating.*freeing.*allocating.*freeing.*done" } */