OSDN Git Service

* fold-const.c (fold) <TRUNC_MOD_EXPR>: The transformation "X % -Y"
[pf3gnuchains/gcc-fork.git] / gcc / ggc-page.c
index 1c625e6..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;
@@ -477,10 +483,6 @@ static void compute_inverse (unsigned);
 static inline void adjust_depth (void);
 static void move_ptes_to_front (int, int);
 
-#ifdef ENABLE_GC_CHECKING
-static void poison_pages (void);
-#endif
-
 void debug_print_page_list (int);
 static void push_depth (unsigned int);
 static void push_by_depth (page_entry *, unsigned long *);
@@ -650,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)
@@ -1042,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;
@@ -1095,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;
 
@@ -1149,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;
@@ -1342,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;
          }
 
@@ -1655,7 +1689,7 @@ ggc_pop_context (void)
 \f
 /* Unmark all objects.  */
 
-static inline void
+static void
 clear_marks (void)
 {
   unsigned order;
@@ -1700,7 +1734,7 @@ clear_marks (void)
 /* Free all empty pages.  Partially empty pages need no attention
    because the `mark' bit doubles as an `unused' bit.  */
 
-static inline void
+static void
 sweep_pages (void)
 {
   unsigned order;
@@ -1744,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])
@@ -1764,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...  */
@@ -1774,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;
                }
            }
@@ -1785,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;
@@ -1809,7 +1867,7 @@ sweep_pages (void)
 #ifdef ENABLE_GC_CHECKING
 /* Clobber all free objects.  */
 
-static inline void
+static void
 poison_pages (void)
 {
   unsigned order;
@@ -1855,6 +1913,49 @@ poison_pages (void)
        }
     }
 }
+#else
+#define poison_pages()
+#endif
+
+#ifdef ENABLE_GC_ALWAYS_COLLECT
+/* Validate that the reportedly free objects actually are.  */
+
+static void
+validate_free_objects (void)
+{
+  struct free_object *f, *next, *still_free = NULL;
+
+  for (f = G.free_object_list; f ; f = next)
+    {
+      page_entry *pe = lookup_page_table_entry (f->object);
+      size_t bit, word;
+
+      bit = OFFSET_TO_BIT ((char *)f->object - pe->page, pe->order);
+      word = bit / HOST_BITS_PER_LONG;
+      bit = bit % HOST_BITS_PER_LONG;
+      next = f->next;
+
+      /* Make certain it isn't visible from any root.  Notice that we
+        do this check before sweep_pages merges save_in_use_p.  */
+      if (pe->in_use_p[word] & (1UL << bit))
+       abort ();
+
+      /* If the object comes from an outer context, then retain the
+        free_object entry, so that we can verify that the address
+        isn't live on the stack in some outer context.  */
+      if (pe->context_depth != G.context_depth)
+       {
+         f->next = still_free;
+         still_free = f;
+       }
+      else
+       free (f);
+    }
+
+  G.free_object_list = still_free;
+}
+#else
+#define validate_free_objects()
 #endif
 
 /* Top level mark-and-sweep routine.  */
@@ -1892,41 +1993,10 @@ ggc_collect (void)
 
   clear_marks ();
   ggc_mark_roots ();
-
-#ifdef ENABLE_GC_CHECKING
   poison_pages ();
-#endif
-
+  validate_free_objects ();
   sweep_pages ();
 
-#ifdef ENABLE_GC_ALWAYS_COLLECT
-  /* Validate that the reportedly free objects actually are.  */
-  {
-    struct free_object *f, *n;
-    for (f = G.free_object_list; f ; f = n)
-      {
-       page_entry *pe = lookup_page_table_entry (f->object);
-
-       /* If the page entry is null, that means the entire page is free.
-          Otherwise, we have to examine the in-use bit for the object.  */
-       if (pe != NULL)
-         {
-           size_t bit, word;
-           bit = OFFSET_TO_BIT ((char *)f->object - pe->page, pe->order);
-           word = bit / HOST_BITS_PER_LONG;
-           bit = bit % HOST_BITS_PER_LONG;
-
-           if (pe->in_use_p[word] & (1UL << bit))
-             abort ();
-         }
-
-       n = f->next;
-       free (f);
-      }
-    G.free_object_list = NULL;
-  }
-#endif
-
   G.allocated_last_gc = G.allocated;
 
   timevar_pop (TV_GC);