OSDN Git Service

PR optimization/13424 (hppa), bootstrap/14462, c/14828
[pf3gnuchains/gcc-fork.git] / gcc / ggc-page.c
index e6f7846..4fc6887 100644 (file)
@@ -1,5 +1,6 @@
 /* "Bag-of-pages" garbage collector for the GNU compiler.
-   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -246,6 +247,11 @@ typedef struct page_entry
      this is the last page-entry.  */
   struct page_entry *next;
 
+  /* The previous page-entry with objects of the same size, or NULL if
+     this is the first page-entry.   The PREV pointer exists solely to
+     keep the cost of ggc_free manageable.  */
+  struct page_entry *prev;
+
   /* The number of bytes allocated.  (This will always be a multiple
      of the host system page size.)  */
   size_t bytes;
@@ -646,12 +652,12 @@ static inline char *
 alloc_anon (char *pref ATTRIBUTE_UNUSED, size_t size)
 {
 #ifdef HAVE_MMAP_ANON
-  char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
-                             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  char *page = mmap (pref, size, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 #endif
 #ifdef HAVE_MMAP_DEV_ZERO
-  char *page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
-                             MAP_PRIVATE, G.dev_zero_fd, 0);
+  char *page = mmap (pref, size, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE, G.dev_zero_fd, 0);
 #endif
 
   if (page == (char *) MAP_FAILED)
@@ -1038,23 +1044,25 @@ static unsigned char size_lookup[257] =
 /* Typed allocation function.  Does nothing special in this collector.  */
 
 void *
-ggc_alloc_typed (enum gt_types_enum type ATTRIBUTE_UNUSED, size_t size)
+ggc_alloc_typed_stat (enum gt_types_enum type ATTRIBUTE_UNUSED, size_t size
+                     MEM_STAT_DECL)
 {
-  return ggc_alloc (size);
+  return ggc_alloc_stat (size PASS_MEM_STAT);
 }
 
 /* Zone allocation function.  Does nothing special in this collector.  */
 
 void *
-ggc_alloc_zone (size_t size, struct alloc_zone *zone ATTRIBUTE_UNUSED)
+ggc_alloc_zone_stat (size_t size, struct alloc_zone *zone ATTRIBUTE_UNUSED
+                    MEM_STAT_DECL)
 {
-  return ggc_alloc (size);
+  return ggc_alloc_stat (size PASS_MEM_STAT);
 }
 
 /* Allocate a chunk of memory of SIZE bytes.  Its contents are undefined.  */
 
 void *
-ggc_alloc (size_t size)
+ggc_alloc_stat (size_t size MEM_STAT_DECL)
 {
   size_t order, word, bit, object_offset, object_size;
   struct page_entry *entry;
@@ -1091,12 +1099,18 @@ ggc_alloc (size_t size)
       while (new_entry->context_depth >= G.depth_in_use)
        push_depth (G.by_depth_in_use-1);
 
-      /* If this is the only entry, it's also the tail.  */
+      /* If this is the only entry, it's also the tail.  If it is not
+        the only entry, then we must update the PREV pointer of the
+        ENTRY (G.pages[order]) to point to our new page entry.  */
       if (entry == NULL)
        G.page_tails[order] = new_entry;
+      else
+       entry->prev = new_entry;
 
-      /* Put new pages at the head of the page list.  */
+      /* Put new pages at the head of the page list.  By definition the
+        entry at the head of the list always has a NULL pointer.  */
       new_entry->next = entry;
+      new_entry->prev = NULL;
       entry = new_entry;
       G.pages[order] = new_entry;
 
@@ -1145,11 +1159,23 @@ ggc_alloc (size_t size)
       && entry->next != NULL
       && entry->next->num_free_objects > 0)
     {
+      /* We have a new head for the list.  */
       G.pages[order] = entry->next;
+
+      /* We are moving ENTRY to the end of the page table list.
+        The new page at the head of the list will have NULL in
+        its PREV field and ENTRY will have NULL in its NEXT field.  */
+      entry->next->prev = NULL;
       entry->next = NULL;
+
+      /* Append ENTRY to the tail of the list.  */
+      entry->prev = G.page_tails[order];
       G.page_tails[order]->next = entry;
       G.page_tails[order] = entry;
     }
+#ifdef GATHER_STATISTICS
+  ggc_record_overhead (OBJECT_SIZE (order), OBJECT_SIZE (order) - size PASS_MEM_STAT);
+#endif
 
   /* Calculate the object's address.  */
   result = entry->page + object_offset;
@@ -1338,22 +1364,34 @@ ggc_free (void *p)
 
     if (pe->num_free_objects++ == 0)
       {
+       page_entry *p, *q;
+
        /* If the page is completely full, then it's supposed to
           be after all pages that aren't.  Since we've freed one
           object from a page that was full, we need to move the
-          page to the head of the list.  */
+          page to the head of the list. 
 
-       page_entry *p, *q;
-       for (q = NULL, p = G.pages[order]; ; q = p, p = p->next)
-         if (p == pe)
-           break;
+          PE is the node we want to move.  Q is the previous node
+          and P is the next node in the list.  */
+       q = pe->prev;
        if (q && q->num_free_objects == 0)
          {
            p = pe->next;
+
            q->next = p;
+
+           /* If PE was at the end of the list, then Q becomes the
+              new end of the list.  If PE was not the end of the
+              list, then we need to update the PREV field for P.  */
            if (!p)
              G.page_tails[order] = q;
+           else
+             p->prev = q;
+
+           /* Move PE to the head of the list.  */
            pe->next = G.pages[order];
+           pe->prev = NULL;
+           G.pages[order]->prev = pe;
            G.pages[order] = pe;
          }
 
@@ -1740,10 +1778,17 @@ sweep_pages (void)
          /* Remove the page if it's empty.  */
          else if (live_objects == 0)
            {
+             /* If P was the first page in the list, then NEXT
+                becomes the new first page in the list, otherwise
+                splice P out of the forward pointers.  */
              if (! previous)
                G.pages[order] = next;
              else
                previous->next = next;
+           
+             /* Splice P out of the back pointers too.  */
+             if (next)
+               next->prev = previous;
 
              /* Are we removing the last element?  */
              if (p == G.page_tails[order])
@@ -1760,6 +1805,7 @@ sweep_pages (void)
                {
                  /* Move p to the end of the list.  */
                  p->next = NULL;
+                 p->prev = G.page_tails[order];
                  G.page_tails[order]->next = p;
 
                  /* Update the tail pointer...  */
@@ -1770,6 +1816,11 @@ sweep_pages (void)
                    G.pages[order] = next;
                  else
                    previous->next = next;
+
+                 /* And update the backpointer in NEXT if necessary.  */
+                 if (next)
+                   next->prev = previous;
+
                  p = previous;
                }
            }
@@ -1781,8 +1832,19 @@ sweep_pages (void)
          else if (p != G.pages[order])
            {
              previous->next = p->next;
+
+             /* Update the backchain in the next node if it exists.  */
+             if (p->next)
+               p->next->prev = previous;
+
+             /* Move P to the head of the list.  */
              p->next = G.pages[order];
+             p->prev = NULL;
+             G.pages[order]->prev = p;
+
+             /* Update the head pointer.  */
              G.pages[order] = p;
+
              /* Are we moving the last element?  */
              if (G.page_tails[order] == p)
                G.page_tails[order] = previous;